Share
Embed
Transcript
24 slides
-
About me name: 石倉 昇 : noboru_i 所属: 株式会社モンスターラボ 勤務地:
富山県富山市 (2015年からリモート) -
Flutterでアプリを開発してても、 platform-specific codeを実行した いことが、まれによくありますよ ね? ※ platform-specific code = KotlinやSwiftのコード
https://docs.flutter.dev/platform-integration/platform-channels -
イメージ Flutter data class interface iOS data class interface implementation
Android data class interface implementation 全部自分で実装 -
Data class Flutter (Dart) Android (Kotlin) iOS (Swift) @JsonSerializable() class
BatteryResult { BatteryResult({ required this.level, required this.isCharging, }); final int level; final bool isCharging; // fromJson, toJson の定義 } @Serializable data class BatteryResult ( val level: Int val isCharging: Boolean ) struct BatteryResult: Codable { var level: Int var isCharging: Bool } -
Interface / Implementation (1/3) invokeMethodでネイティブコードを実行した結果を、JSON文字列で受 け取ってクラスに変換する。 Flutter (Dart) class BatteryApi
{ static const platform = MethodChannel('samples.flutter.dev/battery'); Future<BatteryResult> getBatteryLevel() async { // ex. {"level": 89, "isCharging": true} final resultJson = await platform.invokeMethod<String>('getBatteryLevel'); return BatteryResult.fromJson(jsonDecode(resultJson)); } } -
Interface / Implementation (2/3) 同じchannel文字列で、同じmethod名であれば、処理して返す。 Android (Kotlin) private val CHANNEL
= "samples.flutter.dev/battery" MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "getBatteryLevel") { val batteryLevel = getBatteryLevel() val isCharging = getIsCharging() val json = Json.encodeToString(BatteryResult(batteryLevel, isCharging)) result.success(json) } } -
Interface / Implementation (3/3) iOS (Swift) let batteryChannel = FlutterMethodChannel(name:
"samples.flutter.dev/battery", binaryMessenger: controller.binaryMessenger) batteryChannel.setMethodCallHandler({ [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in if call.method == "getBatteryLevel" { let batteryLevel = getBatteryLevel() let isCharging = getIsCharging() let batteryResult = BatteryResult(level: batteryLevel, isCharging: isCharging) let encoder = JSONEncoder() result(encoder.encode(batteryResult)) } }) -
そこでpigeon Pigeon is a code generator tool to make communication
between Flutter and the host platform type-safe, easier, and faster. Google翻訳 Pigeon は、Flutter とホスト プラットフォーム間の通信を タイプセーフ 、 簡単 、 高速 にするコード生成ツールです。 https://pub.dev/packages/pigeon -
pigeonを使う手順 1. インターフェースをDartで書く 2. dart run pigeon を実行(コードが自動生成される) 3. 出力されたinterfaceを、Kotlin/Swiftで実装
4. Flutter側から、出力されたDart interfaceを実行する つまり、定義部分を書くのはDartだけで、KotlinとSwiftは実装するだけ。 -
イメージ Flutter data class interface iOS data class interface implementation
Android data class interface implementation これだけ不要になる。 -
Dart interface pigeonへの入力となるコード class BatteryResult { BatteryResult({ required this.level, required
this.isCharging, }); final int level; final bool isCharging; } @HostApi() abstract class BatteryApi { BatteryResult getBatteryLevel(); } -
dart run pigeon 実行 ファイルが出力される dart run pigeon \ --input
pigeons/messages.dart \ --dart_out lib/gen/messages.dart \ --swift_out ios/Classes/messages.g.swift \ --kotlin_out android/app/src/main/kotlin/com/example/pigeon_plugin/Messages.g.kt \ --kotlin_package "com.example.pigeon_plugin" -
実装するKotlinコード class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine)
{ super.configureFlutterEngine(flutterEngine) BatteryApi.setUp( flutterEngine.dartExecutor.binaryMessenger, BatteryApiImplementation(context) ) } } class BatteryApiImplementation(private val context: Context) : BatteryApi { override fun getBatteryLevel(): BatteryResult { val level: Int = ... val isCharging: Boolean = ... return BatteryResult(level, isCharging) } } -
実装するSwiftコード @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application(
_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any ) -> Bool { GeneratedPluginRegistrant.register(with: self) let controller: FlutterViewController = window?.rootViewController as! FlutterView BatteryApiSetup.setUp(binaryMessenger: controller as! FlutterBinaryMessenger, api return super.application(application, didFinishLaunchingWithOptions: launchOptions } } class BatteryApiImplementation: BatteryApi { func getBatteryLevel() throws -> BatteryResult { let level = ... let isCharging = ... return BatteryResult(level: Int64(level), isCharging: isCharging) -
こうなった Flutter data class interface iOS data class interface implementation
Android data class interface implementation