2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

flutterでiOSのWidgetKitを使う

Last updated at Posted at 2022-02-19

##実装方法

  1. flutterのshared_preferencesで表示したい値を保存
  2. flutterのMethodCannelでswiftのコードを呼び出す
  3. swiftで保存した値をUserDefaults(flutterの形式)で取り出す
  4. AppGroupを用いてWidgetKitと連携
  5. UserDefaultsをiOSの形式で保存し直す
  6. WidgetKit側でUserDefaultsを参照し表示

Widgetの値を変更したい場合は、再度MethodCannelを呼び出して、UserDefaultsの値を変更したのち、Widgetを更新すれば良い

##1. flutterのshared_preferencesで表示したい値を保存
main.dart内で次のように実装

int _counter = 0;
final SharedPreferences _prefs = await SharedPreferences.getInstance();
    _prefs.setInt('count', _counter);

##2. flutterのMethodCannelでswiftのコードを呼び出す

static const methodChannel = MethodChannel('[your app name]/sample');
try {
      final int result = await methodChannel.invokeMethod('setDataForWidgetKit');
      print('SET setUserDefaultsForAppGroup: $result');
    } on PlatformException catch (e) {
      print('ERROR setUserDefaultsData: ${e.message}');
    }

##3. swiftで保存した値をUserDefault(flutterの形式)で取り出す
AppDelegate内のApplication関数内に次のコードを追加

let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: "[your app name]/sample",
                                           binaryMessenger: controller.binaryMessenger)
        channel.setMethodCallHandler({
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            
            if call.method == "setDataForWidgetKit"  {
                self.setUserDefaultsForAppGroup(result: result)
                
            }
            
            result(FlutterMethodNotImplemented)
            return
        })

[your app name]/sampleという名前のMethodCannelの、setDataForWidgetKit関数がflutterからinvokeされたら、swiftのsetUserDefaultsForAppGroup関数を呼び出すという意味である。

##4. AppGroupを用いてWidgetKitと連携
Xcode上のTARGETのRunner->Signing & Capabilities -> + CapabilityからApp Groupを追加
グループの名前は名前は慣例的にgroup.[bundle id]とする
次に、File -> New -> TargetからWidget Extensionを追加する

##5. UserDefaultsをiOSの形式で保存し直す
AppDelegate.swift内のAppDalegateクラス内に以下の関数を追加する

private func setUserDefaultsForAppGroup(result: FlutterResult) {
        
        guard let userDefaults = UserDefaults(suiteName: "group.[your bundle id]") else {
            return result(FlutterError(code: "UNAVAILABLE",
                                       message: "setUserDefaultsForAppGroup Failed",
                                       details: nil))
        }
       
        let defaults = UserDefaults.standard
        let count = defaults.value(forKey: "flutter.count") as? Int
        
        userDefaults.setValue(count, forKey: "count")
        
        if #available(iOS 14.0, *) {
            WidgetCenter.shared.reloadAllTimelines()
        }
        result(true)
       
    }

flutter.countというUserDefaults(flutterとSwiftでデータを共有するためのもの)を取得し、countというUserDefaults(App Group内でデータを共有するためのもの)に定義し直している。
また、iOS14.0以降の端末でWidgetを更新するようにしている

##6. WidgetKit側でUserDefaultを参照し表示

最後にWidgetKitのテンプレートを修正して、値を表示させれば良い
struct SimpleEntry内にプロパティを追加

let count: Int

getSnapshot関数内に以下のコードを追加する

let userDefaults = UserDefaults(suiteName: "group.[your bundle id]")
let countData = userDefaults?.value(forKey: "count") as? Int

最後にmy_widgetEntryViewのbodyの値を次のように変更する

Text(String(entry.count))

あとはnull Saftyに注意しながら、entryの引数を修正していけば実装できる。

##つまずいたところ
・Swiftの機能であるApp GroupやUserDefaultsの仕組みをある程度理解しなければならない
・swiftのコードの実行時にエラーやログがまともに出ないため、手探りでミスを見つけなければならない
・userDefaultsやMethodCannelで使うKeyのタイプミスで時間が取られる可能性がある
・WidgetKitのUIを作るとき、結局ある程度はswiftUIを理解しなければならない
・flutterに必ずresultを返さないと例外が発生する

##参考資料
以下の記事がわかりやすく参考になった。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?