Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How to handle 3rd-Party Apps in a plugin packages in Flutter

How to handle 3rd-Party Apps in a plugin packages in Flutter

73e023e76c881293c494a350b1b7baa2?s=128

Katsumi Onishi

August 28, 2018
Tweet

Transcript

  1. Handling 3rd-Party Apps in a plugin packages @katsummy - Android

    Engineer
  2. Flutter Plugin Package Plugin Package iOS Host FlutterViewController AppDelegate iOS

    platform APIs 3rd-Party App Android Host FlutterView Activity Android platform APIs 3rd-Party App App Platform Channels
  3. App / Package / Plugin app : アプリケーション package :

    共有モジュール(Dart) plugin : プラットフォームの実装を持つ共有モジュール
  4. Platform Channels プラットフォーム固有のAPIと通信する - Method Channel - Event Channel

  5. Method Channel ホストのメソッドを呼び出してプラットフォームのAPIを実行し、結 果を戻り値として受け取ります。 Flutter App iOS/Android Call Method Return

    Value (Synchronous)
  6. Event Channel ブロードキャストストームの受信者をホストに登録し、コールバッ クで非同期にプラットフォームイベントを受信します。 Flutter App iOS/Android BroadcastStream Listener Event

    (Asynchronous) Event
  7. Method Channel Implementation

  8. Method Channel - Android Implement (1/2) public class HelloPlugin implements

    MethodCallHandler { // static method. public static void registerWith(Registrar registrar) { // 1. MethodChannelを作成 final MethodChannel channel = new MethodChannel(registrar.messenger(), "hello"); // 2. MethodChannelにPluginを登録 HelloPlugin instance = new HelloPlugin(); channel.setMethodCallHandler(instance); } $ flutter create --template=plugin hello
  9. Method Channel - Android Implement (2/2) @Override public void onMethodCall(MethodCall

    call, Result result) { // 3. FlutterからのMethodCallを受け取る if (call.method.equals("getPlatformVersion")) { // 4. Flutterへ結果をコールバックする if (/*condition*/) { // 4-1. Success result.success("Android " + android.os.Build.VERSION.RELEASE); } else { // 4-2. Error result.error("ERROR", "errorMessage", null): } } else { // 4-2. NotImplemented Error result.notImplemented(); } } }
  10. Method Channel - iOS Implement (1/2) @interface HelloPlugin : NSObject<FlutterPlugin>

    @end @implementation HelloPlugin // Implemented by the iOS part of a FlutterPlugin. + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { // 1. MethodChannelを作成 FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"hello" binaryMessenger:[registrar messenger]]; // 2. MethodChannelにPluginを登録 HelloPlugin* instance = [[HelloPlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:channel]; }
  11. Method Channel - iOS Implement (2/2) - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {

    // 3. FlutterからのMethodCallを受け取る if ([@"getPlatformVersion" isEqualToString:call.method]) { // 4. Flutterへ結果をコールバックする if (/*condition*/) { // 4-1. Success result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); } else { // 4-2. Error result([FlutterError errorWithCode:@"ERROR" message:"errorMessage" details:nil]); } } else { // 4-2. NotImplemented Error result(FlutterMethodNotImplemented); }
  12. Method Channel - Flutter Implement class Hello { // 1.

    MethodChannelを作成 static const MethodChannel _channel = const MethodChannel('hello'); static Future<String> get platformVersion async { // Platform messages may fail, so we use a try/catch PlatformException. try { // 2. メソッドの呼び出し final String version = await _channel.invokeMethod('getPlatformVersion'); return version; } on PlatformException catch (e) { debugPrint(${e}); return null; } } }
  13. Event Channel Implementation

  14. Event Channel - Android Implement (1/4) public class HelloPlugin implements

    EventChannel.StreamHandler { // 1. StreamHandlerのメソッドを実装 @Override public void onListen(Object arguments, EventChannel.EventSink events) { } @Override public void onCancel(Object arguments) { }
  15. Event Channel - Android Implement (2/4) public class HelloPlugin implements

    EventChannel.StreamHandler { private EventChannel.EventSink _eventSink; public static void registerWith(Registrar registrar) { // 2. EventChannelの作成 final EventChannel eventChannel = EventChannel(registrar.messenger(), "hello"); // 3. EventChannelにPluginを登録 HelloPlugin instance = new HelloPlugin(); eventChannel.setStreamHandler(instance); }
  16. Event Channel - Android Implement (3/4) public class HelloPlugin implements

    EventChannel.StreamHandler { // 1. StreamHandlerのメソッドを実装 @Override public void onListen(Object arguments, EventChannel.EventSink events) { // 4. イベントストリームを設定 _eventSink = events; } @Override public void onCancel(Object arguments) { _eventSink = null; }
  17. Event Channel - Android Implement (4/4) final Runnable runnable =

    new Runnable() { @Override public void run() { if(_eventSink != null) { // 5. イベントをFlutterにエミット if (/*condition*/) { // 5-1. Success _eventSink.success("Hello"); } else { // 5-2. Error _eventSink.error("ERROR", "errorMessage", null); } } } };
  18. Event Channel - iOS Implement (1/4) @interface HelloPlugin : NSObject<FlutterPlugin,

    FlutterStreamHandler> @end // Implemented by the iOS part of a FlutterPlugin and FlutterStreamHandler. @implementation HelloPlugin // 1. StreamHandlerのメソッドを実装 // イベントストリームの設定する要求を処理 - (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { return nil; } // イベントストリームを破棄する要求を処理 - (FlutterError *)onCancelWithArguments:(id)arguments { return nil; }
  19. Event Channel - iOS Implement (2/4) // Implemented by the

    iOS part of a FlutterPlugin and FlutterStreamHandler. @implementation HelloPlugin + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { // 2. EventChannelの作成 FlutterEventChannel* channel = [FlutterEventChannel eventChannelWithName:@"hello" binaryMessenger:[registrar messenger]]; // 3. EventChannelにPluginを登録 HelloPlugin* instance = [[HelloPlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:methodChannel]; }
  20. Event Channel - iOS Implement (3/4) // イベントストリームの設定する要求を処理 - (FlutterError

    *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink { // 4. イベントストリームを設定 _eventSink = eventSink; return nil; } // イベントストリームを破棄する要求を処理 - (FlutterError *)onCancelWithArguments:(id)arguments { _eventSink = nil; return nil; }
  21. Event Channel - iOS Implement (4/4) - (void)emit { [[[NSOperationQueue

    alloc] init] addOperationWithBlock:^{ if(_eventSink != null) { // 5. イベントをFlutterにエミット if (/*condition*/) { // 5-1. Success _eventSink("Hello"); } else { // 5-2. Error _eventSink([FlutterError errorWithCode:@"ERROR" message:"errorMessage" details:nil]); } } }]; } @end
  22. Event Channel - Flutter Implement class Hello { // 1.

    EventChannelの作成 static const EventChannel _channel = const EventChannel('hello'); Hello() { // 2. ブロードキャストストリームのリスナーを設定 _eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); } // 3. イベントストリームの処理 void _onEvent(Object event) { debugPrint(${event}); } // 4. エラーストリームの処理 void _onError(Object error) { debugPrint(${error}); }
  23. How to handle 3rd-Party Apps in a plugin packages

  24. Flutter Plugin Package Plugin Package iOS Host FlutterViewController AppDelegate iOS

    platform APIs 3rd-Party App Android Host FlutterView Activity Android platform APIs 3rd-Party App App Platform Channels
  25. 3rd-Party App Login App Package Login Requeste Plugin 3rd-Party App

    startActivityForResult Result Login Result Result <Method Channel> <Event Channel>
  26. Start Activity of 3rd-Party App in Plugin (1/4) class FlutterLineLoginPlugin(registrar:

    Registrar) : MethodCallHandler, EventChannel.StreamHandler, PluginRegistry.ActivityResultListener { companion object { // static method. @JvmStatic fun registerWith(registrar: Registrar): Unit { FlutterLineLoginPlugin(registrar) } } Registrar + activeContext() + activity() + addActivityResultListener()
  27. Start Activity of 3rd-Party App in Plugin (2/4) init {

    // 1. MethodChannelの作成 val methodChannel = MethodChannel(registrar.messenger(), "net.granoeste/flutter_line_login") // 2. EventChannelの作成 val eventChannel = EventChannel(registrar.messenger(), "net.granoeste/flutter_line_login_result") // 3. MethodChannelとEventChannelにPluginを登録 methodChannel.setMethodCallHandler(this) eventChannel.setStreamHandler(this) // 4. ActivityResultListenerにPluginを登録 registrar.addActivityResultListener(this) }
  28. Start Activity of 3rd-Party App in Plugin (3/4) override fun

    onMethodCall(call: MethodCall, result: Result) { // 5. FlutterからのMethodCallを受け取る when (call.method) { "startLogin" -> { // 6. Activityの起動 val loginIntent = LineLoginApi.getLoginIntent(activity, channelId) activity.startActivityForResult(loginIntent, REQUEST_CODE) // 7. Flutterへは成功を返す result.success(null) } // 8. StreamHandlerのメソッドを実装 override fun onListen(arguments: Any?, events: EventChannel.EventSink) { // 9. EventSinkを保管 _eventSink = events }
  29. Start Activity of 3rd-Party App in Plugin (4/4) // 10.

    onActivityResultを実装 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { val result = LineLoginApi.getLoginResultFromIntent(data) when (result.responseCode) { LineApiResponseCode.SUCCESS -> { // 10. EventSinkに成功を流す eventSink.success(null) } else -> { // 11. EventSinkにエラーを流す eventSink.error(result.responseCode.toString(), result.errorData.message, result.errorData.toString()) } } return true
  30. Start Activity of 3rd-Party App in Package (1/3) class FlutterLineLogin

    { // 1. MethodChannelを作成 static const MethodChannel _methodChannel = const MethodChannel('net.granoeste/flutter_line_login'); // 2. EventChannelの作成 static const EventChannel _eventChannel = const EventChannel('net.granoeste/flutter_line_login_result');
  31. Start Activity of 3rd-Party App in Package (2/3) FlutterLineLogin() {

    // 3. ブロードキャストストリームのリスナーを設定 _eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError); } // 4. イベントストリームの処理 void _onEvent(Object event) { _onLoginSuccess(event); } // 5. エラーストリームの処理 void _onError(Object error) { _onLoginError(error); }
  32. Start Activity of 3rd-Party App in Package (3/3) Function _onLoginSuccess;

    Function _onLoginError; // 6. ログインメソッド startLogin(Function onSuccess, Function onError) async { _onLoginSuccess = onSuccess; _onLoginError = onError; await _methodChannel.invokeMethod('startLogin'); }
  33. Start Activity of 3rd-Party App in App (1/3) // 1.

    インスタンス作成 var _flutterLineLogin = new FlutterLineLogin(); // 2. ログイン await _flutterLineLogin.startLogin( (data) => { // LoginSuccess }, (error) => { // LoginError });
  34. flutter_line_login | Flutter Package https://pub.dartlang.org/packages/flutter_line_login FirebaseSignInWithLine https://github.com/granoeste/FirebaseSignInWithLine