Capacitor Android 源码浅析

您所在的位置:网站首页 安卓mainactivity配置 Capacitor Android 源码浅析

Capacitor Android 源码浅析

2023-12-17 19:37| 来源: 网络整理| 查看: 265

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

本文将按照 Capacitor Android 执行逻辑来分析,只关注流程,不涉及所有代码。基于 Your First Ionic App: Vue 构建,在阅读之前建议自行搭建环境,创建 photo-gallery 项目,最终使用 ionic cap open android 命令打开 Android 项目。

一、找到入口类

Android 页面信息配置在 AndroidManifest.xml 中,打开后,找到 activity 节点,其中包含 action 为 MAIN 和 category 为 LAUNCHER 的就是入口 activity。photo-gallary 工程只有一个 activity,即 MainActivity。

 public class MainActivity extends BridgeActivity {}

MainActivity 继承自 BridgeActivity,不需要额外增加代码,便可完成 capacitor 的初始化。

二、BridgeActivity 2.1 onCreate()

在 onCreate 中加载布局文件 bridge_layout_main.xml,在布局文件中有一个ID为 webview 的控件,用于显示网页信息。

2.2 init()

用于初始化插件,目前被标为 @Deprecated 说明有新的api替代,不是我们分析的重点。

2.3 registerPlugin()

init() 方法标为过时,推荐使用 registerPlugin 来加载插件,photo-gallary 工程中没有用到,暂时放一下,回头再说。

2.4 onStart()

onStart 是 activity 生命周期的第二个方法,在这个方法中对 Bridge 进行初始化。

 @Override public void onStart() {      super.onStart();  ​      if (bridge == null) {          PluginManager loader = new PluginManager(getAssets());  ​          bridgeBuilder.addPlugins(loader.loadPluginClasses());  ​          this.load();     }  }

这个方法一共做了两件事,1. 加载系统插件,2. 创建 Bridge 对象。

loadPluginClasses()

读取 assets 下的 capacitor.plugins.json 文件,解析出 classpath 字段,通过反射获取 Class 对象。

load()

使用 Builder 模式构建 Bridge 对象。

小结:将插件配置信息放到 assets 目录下,新增插件只需要同步更新配置文件即可,程序中不需要做任何修改,这是插件与 SDK 的解耦。

三、Bridge

Bridge 是 Capacitor Android 源码的核心,由它延伸出的 Plugin 更是 Capacitor Android 源码的精华所在。我们一步步来分析。

3.1 create()

在 create() 方法中,对 Bridge 进行初始化,这里主要涉及 webView 的获取,我们是从 BridgeActivity 过来的,所以这里是通过 activity.findViewById(R.id.webview) 取到 webView。Bridge 构造方法依次调用了下面三个方法。

3.2 initWebView()

initWebView 主要对 WebView 进行初始化。如:是否可以执行 javascript 脚本,这里肯定要开启的,不然怎么交互呢(执行不到 @JavascriptInterface 注解方法)。还有一个关键点是 setWebContentsDebuggingEnabled ,只有该方法设置为 true 时,才能通过 chrome 调试(chrome://inspect)。

3.3 registerAllPlugins()

遍历 initialPlugins 列表,解析每一个插件,这个在下一节介绍。

3.4 loadWebView() 生成 appUrl 创建 WebViewLocalServer,主要代理 WebViewClient.shouldInterceptRequest() 方法,用于区分哪些读取本地文件。 设置 WebViewClient,请求的拦截,页面加载完毕等回调。 加载 url

Capacitor Android 都是以 Bridge 展开的,想要获取插件,从 Bridge 中取,想要获取上下文信息,从 Bridge 中取,真是见字如面啊。

四、插件机制

在 registerPlugin() 方法中,获取插件上的 @CapacitorPlugin 注解,得到插件id,并将它缓存到 plugins 中,map 的 value 为封装的插件类 PluginHandle。

PluginHandle 构造方法中,收集所有被打上 @PluginMethod 注解的方法,并将它缓存到 pluginMethods 中,map 的 value 为封装的插件方法类 PluginMethodHandle。

registerPlugin() 方法最后,通过反射实例化了 Plugin 对象。

这个操作有点类似 Retrofit,都是利用注解规范了方法的实现。区别是 Capacitor 中没有用动态代码。

五、消息处理器

initWebView() 执行完毕,创建了 MessageHandler 对象,这是 hybrid App 的交互中枢,有了它才能实现 JS 与 Native 之间的互相调用。

MessageHandler 构造方法中,将当前类设置为 addJavascriptInterface 方法,并设置名为:androidBridge。

5.1 postMessage

postMessage,唯一被打上 @JavascriptInterface 注解的方法,说明它是一个路由方法,解析出参数,交给 callPluginMethod() 干活。

 private void callPluginMethod(String callbackId, String pluginId,                                String methodName, JSObject methodData) {      PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData);      bridge.callPluginMethod(pluginId, methodName, call);  }

callPluginMethod 将参数组装成 PluginCall 对象,并传给 bridge 对象。

5.2 callPluginMethod MessageHandler 中的 callPluginMethod 方法,将 请求参数封装成 PluginCall 对象,并将该请求传递到 bridge.callPluginMethod()。 Bridge.callPluginMethod 通过 pluginId 获取指定的 PluginHandle,没找到则使用 call.errorCallback() 反馈给前端。找到的话,执行该插件的 invoke 方法。 PluginHandle.invoke 先判断 Plugin 实例是否存在,不存在,调用 load 去反射创建对象。存在,则通过方法名去 pluginMethods 中查找 PluginMethodHandle 对象,最终通过反射执行该方法。

到这里,完成了 js 到 native 层的方法执行。

5.3 PluginCall

PluginCall 是一个模型类,它将网页端的方法进行了抽象化:

 private final String pluginId;  private final String methodName;  private final JSObject data;

从这几个成员变量可以看出,它将一类方法进行了模块化,每一个模块即是一个插件。操作的结果通过 msgHandler.sendResponseMessage(); 投递到 MessageHandler 中,并将返回的数据封装为 PluginResult 对象。最后执行 webView.evaluateJavascript() 方法,完成 native 到 js 层的回调。

 final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";  final WebView webView = this.webView;  webView.post(() -> webView.evaluateJavascript(runScript, null));

第一行代码表示,在 Capacitor 下有一个 fromNative 方法,将它挂载到 window 对象,这样便可以接收 native 返回的数据了。

小结:postMessage 收到 js 消息后,首先根据 pluginId 去找插件,找到后,再根据 methodName 去找对应的方法,最终通过反射执行该方法。

六、总结

本篇按照插件的加载流程,插件的执行流程展开,并没有涉及所有类。

整个 Capacitor Android 代码清晰易懂,各类业务被封装成了独立的插件,通过 Bridge 对象进行管理。只要使用过 Retrofit,并且有 js 与 native 交互经验的同学,都可以顺利掌握。通读源码后,我们要提高警惕,避免写重复的代码(在本篇指 @JavascriptInterface 不要重复出现),要学会抽象思维,即:如何将分散的逻辑统一成一套可服用的模型。再结合国内生态,想要开发出一套自用的小程序bridge框架不是难事。

Ps: 当我们通过 npm install @capacitor/app 命令安装插件后,刷新 android 工程,会自动将插件的入口信息写入 capacitor.plugins.json 文件。如果是我们自定义的插件,可以通过 registerPlugin() 来加载。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3