1. 程式人生 > >Flutter與Android原生程式碼互動

Flutter與Android原生程式碼互動

一、概述

Flutter正式版已經出了一段時間了,作為剛入門的一個菜鳥而言,我還需要更多的學習。
最近開始的flutter專案用到了分享功能,但是到目前為止,微信,QQ等還沒有出對flutter分享的SDK,這就需要用到flutter與Android和ios的原生互動。下面僅關於flutter與Android原生的互動,希望能給像我一樣的菜鳥們些微的幫助(只有Android是因為ios我還沒開始寫哈哈哈)。

二、開始編碼(以分享功能為例)

  1. 首先在Flutter端建立一個方法呼叫工具類,便於方法呼叫管理:
class ShareUtil {
  ///私有構造方法
ShareUtil._(); ///其中com.dislux.yshangflutter/UMengShare用於唯一識別通道名稱, /// 這個名字後邊會在Android端使用到,必須跟Android端對應呼叫方法中的通道名稱保持一致,否則無法呼叫 static const MethodChannel _channel = const MethodChannel('com.secoo.yshangflutter/share'); ///shareTextWithMenu對應的是Android端可以通過這個名字呼叫對應的方法,如果Flutter端呼叫方法需要傳遞引數,可以用map傳遞,
///如下傳遞了一個map,其中儲存text:text static Future<dynamic> shareTextWithMenu(String text) async { Map<dynamic, dynamic> result = await _channel.invokeMethod('shareTextWithMenu', {"text": text}); return result; } ///Flutter呼叫是否安裝了微信QQ等,需要Android端返回是否安裝,用於flutter端呼叫方法時得到返回值。 ///這個地方我使用了回撥方法onResult
static Future<dynamic> checkInstall(String platform, {Function onResult(bool isInstall)}) async { bool result = await _channel.invokeMethod('checkInstall', {"platform": platform}); print("是否安裝了${platform} =$result"); if (onResult != null) onResult(result); return result; } ///Flutter呼叫三方登入,需要Android端返回是否登入成功,以及使用者資訊。 ///onResult中儲存了是否呼叫成功,以及成功之後獲取到的使用者資訊 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. 然後在Android端對應方法:
public class SharePlugin implements MethodCallHandler, ActivityResultListener {
    private final Registrar registrar;
    private ShareAction mShareAction;

    // 用於Activity中註冊,com.secoo.yshangflutter/share和剛flutter端要相同
    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.secoo.yshangflutter/share");
        channel.setMethodCallHandler(new SharePlugin(registrar));
    }

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

    /// 分享sdk初始化
    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);
    }

    ///方法呼叫,對應上邊呼叫時使用的名字
    @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();
        }
    }

    ///返回值都存在result中,Flutter中呼叫方法_channel.invokeMethod()返回值就是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(), "已取消", 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. 在繼承了FlutterActivity的Activity中註冊:
public class MainActivity extends FlutterActivity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       GeneratedPluginRegistrant.registerWith(this);
       registerCustomPlugin(this);
   }
   ///註冊剛剛寫的原生方法通道
   private static void registerCustomPlugin(PluginRegistry registrar) {
       UmengsharePlugin.registerWith(registrar.registrarFor("com.dislux.yshangflutter/UMengShare"));
   }
}
  1. 在flutter控制元件中呼叫方法,並獲取返回值:
//分享按鈕
 Widget _shareButton() {
   return GestureDetector(
     onTap: () {
       Share.shareTextWithMenu("分享分享測試");
       Share.checkInstall(Platform.QQ, onResult: (bool isInstall) {
         print("是否安裝了QQ =$isInstall");
       });
       Share.login(Platform.QQ, onResult: (Map<String, String> userInfo) {
         print("登入使用者資訊=${userInfo.toString()}");
       });
     },
     child: ...
     );

三、總結

其實總結下來,flutter呼叫Android原生程式碼就一下四點

  1. flutter端建立一個MethodChannel,名字要和Android端的相同,並使用MethodChannel通過唯一方法名對應呼叫Android原生方法。
  2. Android端同樣生成一個MethodChannel,名字要和上步驟Flutter中建立的相同。繼承MethodCallHandler方法後實現onMethodCall(MethodCall call, Result result)方法,通過call拿到上步驟呼叫的唯一方法名實現不同的方法。
  3. 在繼承了FlutterActivity的Activity中註冊步驟2中實現了MethodCallHandler的通道。
  4. 開始在flutter的控制元件中呼叫原生方法。

寫的比較簡單,是以完成專案目前的功能為前提下匆匆記錄的,希望能幫助到一些人。