写点什么

Android WebView 独立进程解决方案 (1),flutter 推送通知

用户头像
Android架构
关注
发布于: 刚刚


image.png


IBinderPool: Webview 进程和主进程的通讯可能涉及到多个 AIDL Binder,从功能上来讲,我们也会把不同功能的接口写成不同的 AIDL Binder,所以 IBinderPool 用于满足调用方根据不同类型获取不同的 Binder。


interface IBinderPool {IBinder queryBinder(int binderCode); //查找特定 Binder 的方法}


IWebAidlInterface: 最核心的 AIDL Binder,这里把 WebView 进程对主进程的每一个调用看做一次 action, 每个 action 都会有唯一的 actionName, 主进程会提前注册好这些 action,action 也有级别 level,每次调用结束通过 IWebAidlCallback 返回结果


interface IWebAidlInterface {


/**


  • actionName: 不同的 action, jsonParams: 需要根据不同的 action 从 map 中读取并依次转成其他*/void handleWebAction(int level, String actionName, String jsonParams, in IWebAidlCallback callback);


}


IWebAidlCallback: 结果回调


interface IWebAidlCallback {void onResult(int responseCode, String actionName, String response);}


为了维护独立进程和主进程之间的连接,避免每次 aidl 调用时都去重新进行 binder 连接和获取,需要专门提供一个类去维护连接,并根据条件返回 Binder. 这个类就叫做 RemoteWebBinderPool


public class RemoteWebBinderPool {


public static final int BINDER_WEB_AIDL = 1;


private Context mContext;private IBinderPool mBinderPool;private static volatile RemoteWebBinderPool sInstance;private CountDownLatch mConnectBinderPoolCountDownLatch;


private RemoteWebBinderPool(Context context) {mContext = context.getApplicationContext();connectBinderPoolService();}


public static RemoteWebBinderPool getInstance(Context context) {if (sInstance == null) {synchronized (RemoteWebBinderPool.class) {if (sInstance == null) {sInstance = new RemoteWebBinderPool(context);}}}return sInstance;}


private synchronized void connectBinderPoolService() {mConnectBinderPoolCountDownLatch = new CountDownLatch(1);Intent service = new Intent(mContext, MainProHandleRemoteService.class);mContext.bindService(service, mBinderPoolConnection, Context.BIND_AUTO_CREATE);try {mConnectBinderPoolCountDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}}


public IBinder queryBinder(int binderCode) {IBinder binder = null;try {if (mBinderPool != null) {binder = mBinderPool.queryBinder(binderCode);}} catch (RemoteException e) {e.printStackTrace();}return binder;}


private ServiceConnection mBinderPoolConnection = new ServiceConnection() { // 5


@Overridepublic void onServiceDisconnected(ComponentName name) {


}


@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {mBinderPool = IBinderPool.Stub.asInterface(service);try {mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient, 0);} catch (RemoteException e) {e.printStackTrace();}mConnectBinderPoolCountDownLatch.countDown();}};


private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() { // 6@Overridepublic void binderDied() {mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient, 0);mBinderPool = null;connectBinderPoolService();}};


public static class BinderPoolImpl extends IBinderPool.Stub {


private Context context;


public BinderPoolImpl(Context context) {this.context = context;}


@Overridepublic IBinder queryBinder(int binderCode) throws RemoteException {IBinder binder = null;switch (binderCode) {case BINDER_WEB_AIDL: {binder = new MainProAidlInterface(context);break;}default:break;}return binder;}}


}


从代码中可以看到这个连接池连接的是主进程 MainProHandleRemoteService.


public class MainProHandleRemoteService extends Service {@Nullable@Overridepublic IBinder onBind(Intent intent) {Binder mBinderPool = new RemoteWebBinderPool.BinderPoolImpl(context);return mBinderPool;}}

Native-Web 交互和接口管理

一次完整的 Web 页面和 Native 交互过程是这样的:


  1. Native 打开页面时注册接口:“webView.addJavascriptInterface(jsInterface, "webview");” 其中 jsInterface 是 JsRemoteInterface 类的实例:


public final class JsRemoteInterface {@JavascriptInterfacepublic void post(String cmd, String param) {...}


  1. Web 页面通过“window.webview.post(cmd,JSON.stringify(para))”调用 native;

  2. Native(即 Webview 进程)收到调用之后,通过 IWebAidlInterface 实例传递给主进程执行;

  3. 主进程收到 action 请求之后,根据 actionname 分发处理,执行结束之后通过 IWebAidlCallback 完成进程间回调。


其中,通用的 Action 结构如下:


public interface Command {


String name();


void exec(Context context, Map params, ResultBack resultBack);}


根据不同的 Level 将所有的 command 提前注册好, 以 BaseLevelCommand 为例:


public class BaseLevelCommands {


private HashMap<String, Command> commands;private Context mContext;


public BaseLevelCommands(Context context) {this.mContext = context;registerCommands();}


private void registerCommands() {commands = new HashMap<>();registerCommand(playVideoByNativeCommand);}


private Command playVideoByNativeCommand = new Command() {@Overridepublic String name() {return "videoPlay";}


@Overridepublic void exec(Context context, Map params, ResultBack resultBack) {if (params != null) {String videoUrl = (String) params.get("url");


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


if (!TextUtils.isEmpty(videoUrl)) {String suffix = videoUrl.substring(videoUrl.lastIndexOf(".") + 1);DJFullScreenActivity.startActivityWithLanscape(context, videoUrl, DJFullScreenActivity.getVideoType(suffix), DJVideoPlayer.class, " ");}}}};}

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android WebView独立进程解决方案(1),flutter推送通知