Інтеграція React SPA або статичних HTML-сторінок у React Native за допомогою React-native-static-server і WebView

Усі статті, обговорення, новини про Mobile — в одному місці. Підписуйтеся на телеграм-канал!

Всім привіт. Мене звати Нікіта Усіченко, я Front-end developer в компанії MEV.

У цій статті я розпишу інструкцію з інтеграції React Single Page Application (SPA) або статичної HTML-сторінки в застосунок React Native за допомогою react-native-static-server та WebView для платформ iOS та Android.

Цей гайд буде корисний для розробників, які бажають розширити можливості мобільних застосунків за допомогою вебфункцій. Для отримання практичних прикладів перегляньте репозиторії на GitHub: card-caster-web і card-caster-go.

Вступ

Уявіть світ, у якому всі мобільні застосунки не тільки бездоганно працюють, але й можуть похвалитись привабливим візуальним дизайном. Звучить трохи фантастично? Коли ми маємо справу з React Native, це завдання справді може бути дещо складним, особливо, якщо нам потрібно додати хитромудрі анімації або крутий дизайн.

Часто вебсайти справляються із цим набагато краще. Особливо відчутна різниця, якщо ви спробуєте додати у застосунок сторінку з великою кількістю рухомих зображень чи складних даних. Те, що виглядає чудово на сайті, у React Native може працювати повільно або не працювати взагалі.

А тепер уявіть, що ми можемо взяти найкращі частини вебсайту (зокрема ті самі ефектні анімації) та додати їх у свій react-native застосунок. Ба більше, якщо ви вже створили вебсайт, вам не доведеться створювати все заново для застосунку.

Власне, саме про це ми й будемо говорити далі: грубо кажучи, як розмістити мінівеб-сайт у застосунку React Native.

Основи

Перш ніж ми заглибимося в інструкції, познайомимось з основними елементами нашого проєкту.

React Single Page Application (SPA), або HTML-сторінка

Я надам інструкцію із запуску React Single Page Application (SPA) у React Native-застосунку. А якщо ви працюєте з простими HTML-сторінками, ті ж кроки підійдуть і для них.

До кінця ви будете точно знати, як інтегрувати будь-який вебконтент у React Native-застосунок, покращуючи його функціональність і зручність для користувача.

React Native

React Native — це щось на кшталт набору інструментів, який дозволяє вам створити застосунки як на Android, так і на iOS.

Навіщо їх змішувати

Іноді у вашому застосунку потрібно показати щось справді круте чи складне, наприклад гру чи графік, який рухається та змінюється. Зробити це в React Native може бути складно, і застосунок може працювати повільно.

Але у деяких випадках зробити це у вигляді SPA може бути простіше і краще.

Як ми це робимо

Щоб цей мікс працював, ми використовуємо два помічники: response-native-static-server та WebView. Статичний сервер нагадує мінімережу, яка працює всередині вашого телефону і містить ваш SPA.

WebView — це вікно вашої програми, в якому відображається ваш SPA, як у мінібраузері.

Об’єднавши ці два компоненти, ми створимо у вашому застосунку місце, де вебконтент зможе жити та відтворюватися так само легко, як на комп’ютері.

Налаштування

Створіть ваш вебзастосунок

Якщо ви починаєте з нуля з React SPA, налаштуйте свій проєкт за допомогою create-react-app для швидкого старту:

npx create-react-app my-web-app

Потім розробіть свій односторінковий вебзастосунок (SPA) за бажання, переконавшись, що він є адаптивним для мобільних пристроїв, або скористайтеся наявним прикладом SPA.

Створіть свій застосунок на React Native

На момент написання цієї статті актуальною є версія React Native 0.72.6. Для початку роботи з цією версією ініціалізуйте свій проєкт, виконавши наступну команду:

npx react-native init CardCasterGo --version 0.72.6

Якщо ви віддаєте перевагу автоматичному використанню останньої стабільної версії, просто виконайте наступну команду:

npx react-native init CardCasterGo

Або використай наявний react-native app example.

Встановлення статичного сервера та додаткових залежностей

Ми використовуватимемо @dr.pogodin/react-native-static-server для надання вебконтенту в межах застосунку. Це підтримувана версія оригінального futurepress/react-native-static-server, яка забезпечує сумісність з нашими поточними інтерфейсами.

Ми будемо встановлювати версію 0.6.0-alpha.8, але слід зазначити, що є новіші версії. Тож якщо вам цікаво, у цій статті ви знайдете посилання на ці новіші версії та зможете використовувати їх, якщо вони відповідають вимогам вашого проєкту.

Встановіть статичний сервер та додаткові необхідні бібліотеки, виконавши команду:

yarn add @dr.pogodin/[email protected] react-native-fs react-native-webview

Ця команда встановлює react-native-static-server, react-native-fs для доступу до файлової системи, і react-native-webview для рендерингу вебзмісту в межах застосунку.

Не забудьте перейти в папку iOS та виконати команду:

pod install

Підготовка вебконтенту

Тепер, коли налаштовано ваше середовище розробки, час готувати вебконтент для інтеграції.

Незалежно від того, чи ви працюєте з React SPA або простішою HTML-сторінкою, процес передбачає, що контент готовий для подачі у вашому застосунку React Native.

Після завантаження прикладу SPA або створення власного перейдіть до каталогу проєкту в терміналі та виконайте команду:

npm run build

Ця команда компілює ваш застосунок у статичні файли для виробництва в каталозі збірки.

Перевірте ваш білд

Відкрийте папку зі збіркою та переконайтеся, що вона містить файл index.html разом з необхідними JavaScript та CSS ресурсами. Ви можете запустити збірку за допомогою наступної команди:

npx serve -s build

Загальні поради

  • Переконайтеся, що ваш вебконтент є адаптивним. Він повинен виглядати добре на різних розмірах екрана, зокрема на мобільних екранах.
  • Використовуйте відносні шляхи для ресурсів у ваших HTML- або SPA-файлах. Це гарантує, що файли можна знайти за обслуговування з різних базових каталогів у середовищі React Native.
  • Оптимізуйте зображення та мінімізуйте CSS та JavaScript для покращення часу завантаження.
  • Тестуйте свій вебконтент у різних браузерах, щоб гарантувати сумісність, оскільки WebView може поводитися по-різному на iOS та Android.

Налаштування статичного сервера для iOS

Для iOS після збірки вебзастосунка перше, що вам потрібно зробити, — це перемістити теку build в корінь вашого застосунку React Native. Це гарантує правильне розташування контенту в структурі вашого проєкту для зручного доступу та інтеграції.

Ось як це зробити:

  1. Знайдіть теку build у вашому проєкті вебзастосунка. Ця тека містить зібрані статичні файли вашого вебконтенту.
  2. Перетягніть цю теку build в кореневий каталог вашого проєкту React Native. Там розташовані файли App.js та package.json вашого застосунку.

Коли ви переконаєтесь, що тека build перебуває у правильному місці, виконуйте ці кроки в Xcode, щоб упакувати вміст із вашим iOS-застосунком:

Перейдіть до теки ios у каталозі вашого проєкту React Native та відкрийте її, щоб запустити Xcode.

У Xcode клацніть на навігаторі проєкту та розгорніть першу теку, названу за іменем вашого проєкту.

Клацніть правою кнопкою миші на імені проєкту або відповідній підгрупі в навігаторі проєкту. Виберіть Add Files to «YourAppName» з контекстного меню.

У діалоговому вікні вибору файлу перейдіть до теки build і виберіть, де зберігається ваш вебконтент.

У діалозі, який з’являється під час додавання теки, переконайтеся, що опція Copy items if needed не відзначена. Це запобігає дублюванню теки в межах проєкту.

Зрештою ваше дерево тек має виглядати приблизно так:

Налаштування статичного сервера в React Native на iOS

У верхній частині вашого файлу імпортуйте StaticServer від @dr.pogodin/react-native-static-server та RNFS від react-native-fs.

import StaticServer from '@dr.pogodin/react-native-static-server';
import RNFS from 'react-native-fs';

Створіть власний хук useStaticServer. Цей хук буде відповідати за життєвий цикл статичного сервера.

const useStaticServer =()=>{
const [url, setUrl] = useState<string>('');
useEffect(() => {
  let server: StaticServer | null = null;
  const startServer = async (): Promise<void> => {
    const path: string = `${RNFS.MainBundlePath}/build`;
    server = new StaticServer(9090, path, {localOnly: true});
    try {
      const serverUrl = await server.start();
      setUrl(serverUrl);
    } catch (error) {
      console.error('Failed to start server:', error);
    }
  };
  startServer();
  return () => server?.stop();
}, []);
return url;
}

У своєму компоненті використовуйте хук useStaticServer для запуску сервера та отримання URL відданого контенту.

const serverUrl = useStaticServer();

Використовуйте компонент WebView з бібліотеки react-native-webview, щоб відображати ваш вебконтент.

import { WebView } from 'react-native-webview';
function MyComponent() {
 const serverUrl = useStaticServer();
 return (
   <WebView source={{ uri: serverUrl }} />
 );
}

Запустіть свою програму на симуляторі або пристрої iOS, щоб переконатися, що вебконтент правильно обслуговується та відображається.

Налаштування статичного сервера для Android

Під час включення вебконтенту до вашого застосунку React Native для Android вам потрібно виконати деякі додаткові кроки порівняно з iOS через конкретні вимоги платформи Android.

Ось покроковий гайд для цього.

Підготовка вебконтенту

Компіляція вебзастосунку. Розпочніть з компіляції вашого вебзастосунку в статичні файли. Зазвичай це призводить до створення папки build, в якій розташований ваш вебконтент.

Ручне переміщення папки build: вручну перемістіть папку build у каталог android/app/src/main/assets у вашому проєкті React Native. Якщо каталог assets відсутній за цим шляхом, створіть його.

Налаштування статичного сервера для Android

Файлова система Android не дозволяє обслуговувати файли безпосередньо з папки assets. Тому потрібен обхідний механізм, щоб зробити ці файли доступними для статичного сервера.

Реалізуйте функцію copyAssetsFolderContents у своєму коді React Native. Ця функція буде копіювати вміст вашої папки build з assets в каталог, який може бути доступний для статичного сервера. Приклад поточної функції:

const ASSETS_FOLDER_NAME: string = 'build';
const DOCUMENT_FOLDER_PATH: string = `${RNFS.DocumentDirectoryPath}/${ASSETS_FOLDER_NAME}`;
const copyAssetsFolderContents = async (
sourcePath: string,
targetPath: string,
): Promise<void> => {
try {
  const items = await RNFS.readDirAssets(sourcePath);
  const targetExists = await RNFS.exists(targetPath);
  if (!targetExists) {
    await RNFS.mkdir(targetPath);
  }
  for (const item of items) {
    const sourceItemPath = `${sourcePath}/${item.name}`;
    const targetItemPath = `${targetPath}/${item.name}`;
    if (item.isDirectory()) {
      await copyAssetsFolderContents(sourceItemPath, targetItemPath);
    } else {
      await RNFS.copyFileAssets(sourceItemPath, targetItemPath);
    }
  }
} catch (error) {
  console.error('Failed to copy assets folder contents:', error);
  throw error;
}
};
copyAssetsFolderContents(ASSETS_FOLDER_NAME, DOCUMENT_FOLDER_PATH)

Використовуйте хук useStaticServer для управління статичним сервером. Цей хук повинен запустити сервер після підтвердження успішного копіювання папки build в доступний каталог.

const useStaticServer = (folderWasCreated: boolean) => {
const [url, setUrl] = useState<string>('');
useEffect(() => {
  let server: StaticServer | null = null;
  const startServer = async (): Promise<void> => {
    const path: string = `${RNFS.DocumentDirectoryPath}/build`;
    server = new StaticServer(9090, path, {localOnly: true});
    try {
      const url = await server.start();
      setUrl(url);
    } catch (error) {
      console.error('Failed to start server:', error);
    }
  };
  if (folderWasCreated) {
    startServer();
  }
  return () => server?.stop();
}, [folderWasCreated]);
return url;
}
const [folderWasCreated, setFolderWasCreated] = useState<boolean>(false);
const url = useStaticServer(folderWasCreated);
useEffect(() => {
copyAssetsFolderContents(ASSETS_FOLDER_NAME, DOCUMENT_FOLDER_PATH)
  .then(() => {
    console.log('Build folder contents copied successfully.');
    setFolderWasCreated(true);
  })
  .catch(error => {
    console.error('Error copying build folder contents:', error);
  });
}, []);

Використовуйте компонент WebView з пакету react-native-webview для відображення контенту, який надається вашим статичним сервером.

<WebView source={{ uri: serverUrl }} />

Опрацювання помилки ERR_CLEARTEXT_NOT_PERMITTED

Часто за використання програми в режимі випуску або під час створення APK для Android виникає помилка ERR_CLEARTEXT_NOT_PERMITTED.

Її поява пов’язана з політикою безпеки Android щодо передачі чіткого тексту (трафік без HTTPS).

Ця проблема широко обговорюється на Stack Overflow. Ось що потрібно для її вирішення:

Створіть файл конфігурації мережі (Network Security Config)

1.1. У вашому проєкті Android перейдіть до директорії res/xml. Якщо цієї директорії не існує, створіть її.

1.2. Створіть новий файл із назвою network_security_config.xml у цій директорії.

1.3. Додайте наступну конфігурацію до цього файлу:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
   <domain-config cleartextTrafficPermitted="true">
       <!-- Insert specific domains here if needed -->
   </domain-config>
   <base-config cleartextTrafficPermitted="false"/>
</network-security-config>

Ця конфігурація дозволяє передачу відкритого тексту (не за HTTPS) для вказаних доменів, забезпечуючи безпечну політику для всіх інших.

Оновіть Android Manifest:

2.1 Відредагуйте файл AndroidManifest.xml, додавши наступний атрибут всередині тегу <application>:

android:networkSecurityConfig="@xml/network_security_config"

Після впровадження цих змін перекомпілюйте та протестуйте свій застосунок у режимі випуску. Забезпечте, що компонент WebView завантажує локальний вміст без спричинення помилки ERR_CLEARTEXT_NOT_PERMITTED.

Висновок

Ми дізналися, як об’єднати найкраще з веброзробки та створення мобільних застосунків, використовуючи React Native. Цей підхід дозволяє легко додавати стильні вебфункції, як-от деталізовані дизайни та анімації, до наших мобільних застосунків.

Зазирніть в репозиторії GitHub, щоб побачити повний приклад та як усе працює разом. Для повного прикладу застосунку:

Завдяки таким інструментам, як react-native-static-server та WebView, а також підтримці спільноти, ми можемо створювати потужні та приємні в користуванні мобільні застосунки. Спробуйте це та побачте, які неймовірні речі ви можете створити!

👍ПодобаєтьсяСподобалось2
До обраногоВ обраному2
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Як додати реакт в реакт, щоб використовувати реакт поки використовуєш реакт.
Не хочу здатися снобом, але якщо чесно, звучить як гайд «як робити не треба».

Іноді у вашому застосунку потрібно показати щось справді круте чи складне, наприклад гру чи графік, який рухається та змінюється. Зробити це в React Native може бути складно, і застосунок може працювати повільно.

Така потреба означає, що стек з самого початку було обрано не правильно, або хтось придумав вимоги, яких не варто було вимагати від поточного стеку. Це приблизно те ж саме, що змусити додаток на реакт нейтів працювати всередині айфрейму на вебі, бо «Іноді у вашому застосунку потрібно показати щось справді круте»

Підписатись на коментарі