Flutter interacts with Android native code

Keywords: Android SDK iOS

I. overview

Flutter's official version has been out for some time. As a beginner, I need to learn more.
Recently, the flutter project has used the sharing function, but so far, there is no SDK for flutter sharing, such as Wechat, QQ, etc., which requires the native interaction between flutter and Android and ios. Here's just about flutter's native interaction with Android, hoping to give some help to rookies like me (only Android because IOS hasn't started writing haha yet).

Start coding (for example, sharing function)

  1. First, a method invocation tool class is created on the Flutter side to facilitate method invocation management.
class ShareUtil {
  /// Private Construction Method
  ShareUtil._();

  /// where com.example/share is used to uniquely identify the channel name,
  /// This name will be used later on the Android side and must be consistent with the channel name in the corresponding invocation method on the Android side, otherwise it cannot be invoked.
  static const MethodChannel _channel =
      const MethodChannel('com.example/share');

  /// shareTextWithMenu corresponds to Android calling the corresponding method by this name. If the Flutter calling method needs to pass parameters, it can be passed by map.
  /// A map is passed in which text is stored:
  static Future<dynamic> shareTextWithMenu(String text) async {
    Map<dynamic, dynamic> result =
        await _channel.invokeMethod('shareTextWithMenu', {"text": text});
    return result;
  }

  /// Whether or not the Flutter call has installed Wechat QQ and so on requires the Android end to return whether it has been installed or not, which is used to get the return value when the flutter end calls the method.
  /// Here I use the callback method onResult
  static Future<dynamic> checkInstall(String platform,
      {Function onResult(bool isInstall)}) async {
    bool result =
        await _channel.invokeMethod('checkInstall', {"platform": platform});
    print("Is it installed? ${platform} =$result");
    if (onResult != null) onResult(result);
    return result;
  }

  /// Flutter calls for tripartite login, requiring the Android side to return whether the login was successful, as well as user information.
  /// onResult stores information about whether or not the call was successful and the user information obtained after the call was successful.
  static Future<dynamic> login(int platform,
      {Function onResult(Map<String, String> userInfo)}) async {
    Map<String, String> result =
        await _channel.invokeMethod('login', {"platform": platform});
    if (onResult != null) onResult(result);
    return result;
  }
}    
  1. Then corresponding method on Android side:
public class SharePlugin implements MethodCallHandler, ActivityResultListener {
    private final Registrar registrar;
    private ShareAction mShareAction;

    // For registration in Activity, the com.secoo.yshangflutter/share and the rigid flutter end should be the same
    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.example/share");
        channel.setMethodCallHandler(new SharePlugin(registrar));
    }

    private SharePlugin(Registrar registrar) {
        this.registrar = registrar;
    }

    /// Shared sdk initialization
    private void init(Context context) {
        UMConfigure.init(context, "5c2f5016b465f54424000446", "umengshare", UMConfigure.DEVICE_TYPE_PHONE, "");//58edcfeb310c93091c000be2 5965ee00734be40b580001a0
        PlatformConfig.setWeixin("wxdc1e388c3822c80b", "3baf1193c85774b3fd9d18447d76cab0");
        PlatformConfig.setQQZone("100424468", "c7394704798a158208a74ab60104f0ba");
        mShareAction = new ShareAction(registrar.activity()).setDisplayList(SHARE_MEDIA.WEIXIN, SHARE_MEDIA.WEIXIN_CIRCLE, SHARE_MEDIA.WEIXIN_FAVORITE, SHARE_MEDIA.QQ, SHARE_MEDIA.QZONE, SHARE_MEDIA.SINA);
    }

    /// Method call, corresponding to the name used in the above call
    @Override
    public void onMethodCall(MethodCall call, Result result) {
        if (call.method.equals("shareTextWithMenu")) {
            String text = call.argument("text");
            shareText(text, result);
        } else if (call.method.equals("login")) {
            int platform = call.argument("platform");
            login(sharePlatForm(platform), result);
        } else if (call.method.equals("checkInstall")) {
            int platform = call.argument("platform");
            boolean flag = UMShareAPI.get(registrar.context()).isInstall(registrar.activity(), sharePlatForm(platform));
            result.success(flag);
        } else {
            result.notImplemented();
        }
    }

    /// The return values all exist in the result, and the return value of the call method _channel.invokeMethod() in Flutter is the value in the result.
    private void shareText(final String text, final Result result) {
        mShareAction.setShareboardclickCallback(new ShareBoardlistener() {
            @Override
            public void onclick(SnsPlatform snsPlatform, SHARE_MEDIA share_media) {
                new ShareAction(registrar.activity()).setPlatform(share_media)
                        .withText(text)
                        .setCallback(new UMShareListener() {
                            @Override
                            public void onStart(SHARE_MEDIA share_media) {
                                LoadingDialog.showLoading(registrar.activity());
                            }

                            @Override
                            public void onResult(SHARE_MEDIA share_media) {
                                LoadingDialog.hideLoading();
                                Map<String, Object> map = new HashMap<>();
                                map.put("code", "000000");
                                result.success(map);
                            }

                            @Override
                            public void onError(SHARE_MEDIA share_media, Throwable throwable) {
                                LoadingDialog.hideLoading();
                                Toast.makeText(registrar.activity(), throwable.getMessage(), Toast.LENGTH_LONG).show();
                                Map<String, Object> map = new HashMap<>();
                                map.put("code", "100000");
                                map.put("msg", throwable.getMessage());
                                result.success(map);
                            }

                            @Override
                            public void onCancel(SHARE_MEDIA share_media) {
                                LoadingDialog.hideLoading();
                                Toast.makeText(registrar.activity(), "Cancelled", Toast.LENGTH_LONG).show();
                                Map<String, Object> map = new HashMap<>();
                                map.put("status", "200000");
                                result.success(map);
                            }
                        });
            }
        }).open();
    }

    private void login(SHARE_MEDIA platform, final Result result) {
        UMShareAPI.get(registrar.activity()).getPlatformInfo(registrar.activity(), platform, new UMAuthListener() {
            @Override
            public void onStart(SHARE_MEDIA share_media) {
                Log.e("login", "onStart");
            }

            @Override
            public void onComplete(SHARE_MEDIA share_media, int i, Map<String, String> map) {
                map.put("code", "000000");
                result.success(map);
            }

            @Override
            public void onError(SHARE_MEDIA share_media, int i, Throwable throwable) {
                Map<String, Object> map = new HashMap<>();
                map.put("code", "100000");
                map.put("msg", throwable.getMessage());
                result.success(map);
            }

            @Override
            public void onCancel(SHARE_MEDIA share_media, int i) {
                Map<String, Object> map = new HashMap<>();
                map.put("code", "200000");
                result.success(map);
            }
        });
    }

    private SHARE_MEDIA sharePlatForm(int index) {
        final SHARE_MEDIA platform;
        switch (index) {
            case 0:
                platform = SHARE_MEDIA.WEIXIN;
                break;
            case 1:
                platform = SHARE_MEDIA.QQ;
                break;
            default:
                platform = SHARE_MEDIA.QQ;
                break;

        }
        return platform;
    }

    @Override
    public boolean onActivityResult(int i, int i1, Intent intent) {
        UMShareAPI.get(registrar.activity()).onActivityResult(i, i1, intent);
        return false;
    }
}
  1. Register in Activity that inherits Flutter Activity:
public class MainActivity extends FlutterActivity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       GeneratedPluginRegistrant.registerWith(this);
       registerCustomPlugin(this);
   }
   /// Register the native method channel just written
   private static void registerCustomPlugin(PluginRegistry registrar) {
       UmengsharePlugin.registerWith(registrar.registrarFor("com.example/share"));
   }
}
  1. Call the method in the flutter control and get the return value:
//Share button
 Widget _shareButton() {
   return GestureDetector(
     onTap: () {
       Share.shareTextWithMenu("Sharing Test");
       Share.checkInstall(Platform.QQ, onResult: (bool isInstall) {
         print("Is it installed? QQ =$isInstall");
       });
       Share.login(Platform.QQ, onResult: (Map<String, String> userInfo) {
         print("Login user information=${userInfo.toString()}");
       });
     },
     child: ...
     );

Three, summary

In summary, there are four points for flutter to call Android native code

  1. The flutter side creates a Method Channel with the same name as the Android side, and calls the Android native method with the unique method name.
  2. The Android side also generates a Method Channel with the same name as the one created in the previous step, Flutter. After inheriting the MethodCallHandler method, the onMethodCall (Result result) method is implemented. Different methods are implemented by calling the unique method name called in the previous step.
  3. The channel of MethodCallHandler is implemented in step 2 of registration in Activeness, which inherits Flutter Activity.
  4. Start calling native methods in flutter's controls.

Writing is relatively simple, on the premise of completing the current functions of the project, and record in a hurry, hoping to help some people.

Posted by Bricktop on Fri, 26 Apr 2019 19:18:36 -0700