Предупреждение о спойлере: React Native нельзя использовать в самом виджете.

Цель: узнать, как создать собственный виджет и поделиться информацией с вашим приложением React Native .

TL; DR: проверьте весь код и следуйте коммитам здесь.

Расширенная функция. Рекомендуется хорошо знать React Native и иметь некоторый опыт разработки для Android / iOS.

Виджет - важное дополнение к приложению и часто очень востребованная функция. К сожалению, вы не можете использовать React Native напрямую для создания виджета. Почему? Потому что iOS имеет ограничение памяти в 16 МБ для расширений приложений, и React Native с самого начала займет большую его часть. Поверьте, я пробовал.

Таким образом, альтернативой является создание каждого виджета изначально с помощью Java на Android и Swift на iOS. И обычно вам нужен виджет, чтобы иметь возможность обмениваться информацией с основным приложением - в данном случае с приложением React Native. Из этого туториала Вы узнаете, как этого добиться.

Я назвал проект ReactNativeCreateWidgetTutorial, , и он будет выглядеть примерно так:

iOS

1. Создайте файлы виджетов.

Создайте виджет (в iOS он называется Today Extension), открыв файл рабочего пространства в Xcode и щелкнув File ›New› Target:

Выберите Today Extension и нажмите Next:

Дайте ему имя и выберите предпочитаемый язык. В этом случае я выберу Swift. Нажмите Готово:

Если Xcode просит активировать схему, нажмите «Активировать».

Вы должны увидеть папку Widget в своем проекте:

Теперь вы должны увидеть виджет на экране виджета, и вы уже можете его активировать:

Теперь давайте проверим структуру виджета. Перейдите в папку виджетов и щелкните файл раскадровки. Нажмите на кнопку помощника-редактора (с двумя кружками в правом верхнем углу экрана):

Как видите, есть две функции: viewDidLoad и widgetPerformUpdate . Функция viewDidLoad запускается каждый раз, когда пользователь переключается на экран виджетов. Итак, это место, где вы должны инициализировать переменные, метки или представления. Функция widgetPerformUpdate вызывается всякий раз, когда вам нужно обновить содержимое виджета.

2. Настройте пользовательский интерфейс виджета.

Вы также можете увидеть ярлык с текстом "Hello World". Давайте настроим этот ярлык, перетащив его в наш код. Щелкните правой кнопкой мыши метку и перетащите New Referencing Outlet прямо в код внутри класса.

Вы должны увидеть ссылку в коде следующим образом:

Давайте изменим текст метки внутри функции viewDidLoad:

override func viewDidLoad() {
 super.viewDidLoad()
 // Do any additional setup after loading the view from its nib.
 //ADD THIS LINE 
 textLabel.text = "My first Widget"
}

Если вы запустите приложение, вы должны увидеть, что метка была инициализирована правильно:

Совет. Вы можете запустить виджет без запуска всего приложения, перейдя в Xcode и выбрав виджет в качестве цели, а затем нажав кнопку «Выполнить»:

3. Создайте канал связи между виджетом и приложением React Native.

Хорошо, теперь самое интересное. Пусть наше приложение React Native будет контролировать, что показывает виджет. Для этого мы должны реализовать способ взаимодействия приложения React Native с виджетом. Мы собираемся сделать это через общее хранилище между виджетом и приложением React Native. Это можно сделать с помощью модуля UserDefaults iOS собственного .

Мы заставим приложение React Native писать в UserDefaults , и виджет будет читать из него. Первая проблема, которую мы обнаруживаем, заключается в том, что нет официального способа взаимодействия React Native с UserDefaults, и . Я не нашел для этого никакой хорошей библиотеки. Итак, давайте реализуем это сами, создав мост между React Native и собственной iOS.

Во-первых, мы создадим общее пространство внутри нашего приложения, которое позволит взаимодействовать между виджетом и приложением. Это можно сделать с помощью групп приложений, которые находятся на вкладке «Возможности».

Давайте активируем его, а затем выберем группу или добавим ее, если она пуста:

Хорошо, теперь, когда у нас включены группы приложений, давайте реализуем способ для React Native писать в UserDefaults, создав собственный мост.

S выберите свой проект и щелкните правой кнопкой мыши, чтобы добавить новый файл:

Выберите Cocoa Touch Class и нажмите Далее:

Поскольку это хранилище, которое будет совместно использоваться виджетом и приложением React Native, назовем его SharedStorage. Выберите Objective-C и нажмите «Далее»:

Теперь вы должны увидеть новые файлы в своем проекте:

Давайте отредактируем эти файлы. Сначала скопируйте это в SharedStorage.h файл:

И это в SharedStorage.m файле:

Важно: измените название группы (group.com.createwidget.pimenta) на то, которое вы создали в группах приложений.

Теперь вы можете позвонить SharedStorage в React Native. Как видно из кода, все, что он делает, это получает JSON и сохраняет его в UserDefaults хранилище.

4. Управляйте содержимым виджета с помощью приложения React Native.

На стороне React Native импортируем модуль:

import { NativeModules } from 'react-native';
const SharedStorage = NativeModules.SharedStorage;

А затем отправим данные в хранилище:

SharedStorage.set(
 JSON.stringify({text: 'This is data from the React Native app'})
);

Вы можете сделать это, например, на своем App.js или там, где вы сочтете целесообразным установить данные в вашем коде React Native:

Теперь все, что осталось, - это заставить виджет считывать данные и вставлять их в пользовательский интерфейс. Мы собираемся подключить виджет к UserDefaults, прочитать его данные, а затем распечатать данные в «Hello World» textLabel.

Перейдите в свой TodayViewController.swift файл в папке виджетов и отредактируйте viewDidLoad функцию, например:

//CHANGE THE GROUP NAME
let userDefaults = UserDefaults(suiteName:"group.com.createwidget.pimenta")
override func viewDidLoad() {
 super.viewDidLoad()
 // Do any additional setup after loading the view from its nib.
 //ADD THIS
 do{
  let shared = userDefaults?.string(forKey: "data")
  if(shared != nil){
   let data = try JSONDecoder().decode(Shared.self, from: shared!.data(using: .utf8)!)
   textLabel.text = data.text
  }
 }catch{
  print(error)
 }
}

Вы можете просмотреть весь файл здесь.

Важно: измените название группы (group.com.createwidget.pimenta) на то, которое вы создали в группах приложений.

Давайте запустим приложение и проверим виджет (обратите внимание, что вам нужно запустить и открыть приложение, чтобы оно написало SharedStorage):

И это все, что касается iOS - теперь часть Android.

Android

1. Создайте файлы виджетов.

Откройте папку Android в Android Studio. Затем в Android Studio щелкните правой кнопкой мыши res ›New› Widget ›App Widget:

Назовите и настройте виджет и нажмите Готово:

В следующем окне будут показаны несколько файлов, которые будут добавлены в проект. В файле Widget.java мы запрограммируем поведение виджета. В остальных файлах мы реализуем компоненты пользовательского интерфейса виджета. Нажмите Добавить:

Теперь, если вы запустите приложение, вы должны увидеть доступный виджет:

Примечание. Если вы сначала изучили руководство для iOS, прокомментируйте строки, в которых вы вызывали SharedStorage, в коде React Native, поскольку он еще не реализован на Android, и это приведет к ошибке.

Хорошо, теперь, когда у нас запущен виджет, давайте немного его настроим.

2. Настройте пользовательский интерфейс виджета.

В Android Studio откройте папку приложения и выберите файл res - ›layout -› widget.xml:

Это открывает макет вашего виджета. Как видите, есть текстовое представление с текстом «ПРИМЕР». Вы можете увидеть более подробную информацию, если нажмете на нее:

Изменим текст ярлыка. Как вы можете видеть в свойствах метки, текст ссылается на «@ string / appwidget_text». Он находится в разрешении ›values› strings.xml. Откройте этот файл, и вы увидите определенный текст:

Если вы измените текст с «ПРИМЕР» на «ПРИВЕТ», сохраните файл и снова запустите приложение. Это будет отражено на виджете. Давай сделаем это:

Хорошо, теперь мы знаем, как настроить виджет. Затем давайте реализуем способ сделать это через приложение React Native.

3. Создайте канал связи между виджетом и приложением React Native.

Хорошо, теперь снова самое интересное. Пусть наше приложение React Native будет контролировать, что показывает виджет. Для этого мы должны реализовать способ взаимодействия приложения React Native с виджетом. Мы собираемся сделать это с помощью общего хранилища между виджетом и приложением React Native. Это можно сделать с помощью модуля SharedPreferences для Android .

Мы заставим приложение React Native писать в SharedPreferences, и виджет будет читать из него. Первая проблема, которую мы обнаруживаем, заключается в том, что нет официального способа взаимодействия React Native с SharedPreferences, и . Я не нашел для этого подходящей библиотеки. Так что давайте реализуем это сами.

Чтобы вызвать SharedPreferences, мы создадим мост между React Native и собственным Android.

Добавьте два файла в свой проект рядом с MainActivity.java с именами SharedStorage.java и SharedStoragePackager.java:

Скопируйте в свой SharedStoragePackager.java файл следующее:

И это в вашем SharedStorage.java файле:

Important: Измените имя пакета com.reactnativecreatewidgettutorial на свое. А также Widget.class к имени вашего класса виджета.

Теперь вы можете вызывать SharedStorage в React Native. Как вы можете видеть из кода, все, что он делает, это получает JSON и сохраняет его в SharedPreferences хранилище, а затем сообщает виджету, чтобы он обновился.

Чтобы Android знал, что ваш модуль существует, добавьте его в список пакетов в вашем MainApplication.java файле.

new SharedStoragePackager()

4. Управляйте содержимым виджета с помощью приложения React Native.

На стороне React Native давайте импортируем модуль.

Примечание. Если вы уже изменили код React Native, пропустите эту часть.

import { NativeModules } from 'react-native';
const SharedStorage = NativeModules.SharedStorage;

А затем отправим данные в хранилище:

SharedStorage.set(
 JSON.stringify({text: 'This is data from the React Native app'})
);

Вы можете сделать это, например, на своем App.js или там, где вы сочтете целесообразным установить данные в вашем коде React Native:

Теперь все, что осталось, - это заставить виджет считывать данные и вставлять их в пользовательский интерфейс. Мы собираемся подключить виджет к SharedPreferences, прочитать его данные и затем распечатать данные на этикетке «HELLO» .

Перейдите в свой Widget.java файл в папке виджетов и импортируйте следующие модули:

import android.content.SharedPreferences;
import org.json.JSONException;
import org.json.JSONObject;

Теперь измените функцию updateAppWidget, например:

static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
 
 try {
  SharedPreferences sharedPref = context.getSharedPreferences("DATA", Context.MODE_PRIVATE);
  String appString = sharedPref.getString("appData", "{\"text\":'no data'}");
  JSONObject appData = new JSONObject(appString);
  // Construct the RemoteViews object
  RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
  views.setTextViewText(R.id.appwidget_text, appData.getString("text"));
  // Instruct the widget manager to update the widget
  appWidgetManager.updateAppWidget(appWidgetId, views);
 }catch (JSONException e) {
  e.printStackTrace();
 }
}

Вы можете просмотреть весь файл здесь.

Мы модифицируем функцию updateAppWidget, которая отвечает за обновление содержимого виджета, чтобы виджет читал из SharedPreferences db и печатал данные на текстовой метке.

Вот и все - теперь приложение React Native контролирует содержимое виджета. Давайте запустим приложение и проверим виджет (обратите внимание, что вам нужно запустить и открыть приложение, чтобы оно могло писать в SharedStorage):

И это все, что касается кодирования. Теперь у вас есть фундамент, на котором вы можете строить остальные части виджета. Проверим окончательные результаты.

Полученные результаты

Код: Отметьте весь код здесь.

Надеюсь, этот урок вам помог.