Android与WebView的插件管理机制

Webview.apk —— Google 官方的私有插件化方案 在 Android 跨入 5.0 版本之后,我们在使用 Android 手机的过程中,可能会发现一个奇特的现象,就是手机里的 WebView 是可以在应用商店升级,而不需要跟随系统 阅读详情

上一篇文章说到,当利用WebViewClient或者WebChromeClient来处理由html页面传过来的请求的时候,都会将对应的服务名称,操作方法和对应的参数数据传给一个叫PluginManager的类。

PluginManager类的作用是什么?

大家知道,当利用Android原生环境的功能,比如照像机,比如相册等,这些功能都是很分散的,说不清楚什么时候是需要这些功能,什么时候是不需要这些功能的,所以我们希望能够像插件一样,需要的时候就加载进来,不需要的时候不去理他,而PluginManager类就是一个这样的管理类。

它主要负责几件事情:

1)进入HTML页面的时候,去加载我们定义好的控件。

mPluginManager = new PluginManager(this);
mPluginManager.loadPlugin();

那么PluginManager怎么知道本个应用要加载多少plugin来去响应由Html页面来的请求呢?

我们是通过一个叫plugin.xml配置文件来定义的。

<plugins>
    <plugin name="App" class="com.lms.xxx.bridge.plugin.App" />
    <plugin name="Toast" class="com.lms.xxx.plugin.Toast" />
    <plugin name="Dialog" class="com.lms.xxx.bridge.plugin.Dialog" />   
    <plugin name="User" class="com.lms.xxx.bridge.plugin.User" />
</plugins>


比如在上面的配置文件中,我们会加载App, Toast, Dialog 和 User 这几个plugin。

可以联想到,Toast和Dialog都是Android原生环境下的显示窗口,我们虽然用html页面来实现界面,但是为了保持整个应用的一致性,我们就会用到原生环境中的Toast或者我们自定义的对话框等控件。

需要用到什么,就在这里定义什么。

我们再来看一下loadPlugin方法:

	public void loadPlugin() {
		int identifier = context.getResources().getIdentifier("plugins", "xml",
				context.getPackageName());
		if (identifier == 0) {
			pluginConfigurationMissing();
		}

		XmlResourceParser xml = context.getResources().getXml(identifier);
		try {

			int eventType = -1;
			while ((eventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
				if (eventType == XmlResourceParser.START_TAG) {
					String name = xml.getName();
					if ("plugin".equals(name)) {
						String pluginName = xml.getAttributeValue(null, "name");
						String className = xml.getAttributeValue(null, "class");
						configs.put(pluginName, className);
					}

				}
			}

		} catch (XmlPullParserException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

可以看到,这就是解析plugins.xml文件,然后将对应的插件类名给放到configs中,configs定义如下:

private HashMap<String, String> configs = new HashMap<String, String>();
private HashMap<String, IPlugin> plugins = new HashMap<String, IPlugin>();

通过loadPlugin方法,我们就将在plugins.xml中定义好的插件,给加载到configs中去了,configs里存放的只是类名,而plugins存放的才是实现,不过我们这里不需要关心这个。

在这里,在plugins.xml文件中定义的name属性就是这个服务名称。

2)根据请求的服务名称和操作方法等,为这个请求找到对应的Plugin去处理。

String execResult = mPluginManager.exec("service", "action", args);

看一下exec方法,

public String exec(String service, String action, JSONObject args) throws PluginNotFoundException {
        IPlugin plugin = getPlugin(service);
	...	
	PluginResult result = plugin.exec(action, args);
	...		
}

在上面的逻辑可以看到,PluginManager会利用getPlugin方法拿出对应的服务,如下:

	public IPlugin getPlugin(String pluginName) throws PluginNotFoundException {
		String className = configs.get(pluginName);
		if(className==null){
			throw new PluginNotFoundException(pluginName);
		}
		if (plugins.containsKey(className)) {
			return plugins.get(className);
		} else {
			return addPlugin(className);
		}
	}


这样,我们就拿到了一个实现了IPlugin接口中的Plugin实现类。

IPlugin是一个接口,其定义如下:

public interface IPlugin {
	
	public static final String SERVICE = "service";
	public static final String ACTION = "action";
	public static final String ARGS = "args";

	/**
	 * 执行请求
	 * 
	 * @param action
	 *            功能
	 * @param args
	 *            参数
	 * @return pluginResult 结果
	 */
	public PluginResult exec(String action, JSONObject args)throws ActionNotFoundException;

里面定义的最重要的方法就是exec方法,每一个我们自定义的插件都要实现这个接口,不过在这里,我们先实现了一个抽象基类Plugin,在里面实现一些公共的逻辑,而对于具体的实现,再由Plugin的子类去继承。

public abstract class Plugin implements IPlugin {

	protected DroidHtml5 context;

比如,我们拿上面的Toast类,其就会继承Plugin,然后根据对应的服务去实现对应的逻辑,调用原生环境的Toast。

public class Toast extends Plugin {

	@Override
	public PluginResult exec(String action, JSONObject args)
			throws ActionNotFoundException {
		if ("makeTextShort".equals(action)) {
			return makeTextShort(args);
		}else if ("makeTextLong".equals(action)) {
			return makeTextLong(args);
		} else {
			throw new ActionNotFoundException("Toast", action);
		}

	}

	private PluginResult makeTextShort(JSONObject args) {

		try {
			String text = args.getString("text");			
			android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show();
		} catch (JSONException e) {
			e.printStackTrace();
			return PluginResult.newErrorPluginResult(e.getMessage());
		}
		return PluginResult.newEmptyPluginResult();
	}
	
	private PluginResult makeTextLong(JSONObject args) {

		try {
			String text = args.getString("text");			
			android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_LONG).show();
		} catch (JSONException e) {
			e.printStackTrace();
			return PluginResult.newErrorPluginResult(e.getMessage());
		}
		return PluginResult.newEmptyPluginResult();
	}

}


从上面的代码,相信大家很容易就能够理解了Plugin机制了。

3)从Html页面来调用。

我们在Android原生环境定义了这么一套Plugin机制,那么在Html里面,也可以有这样的一套接口方法,来对应不同的Plugin,所以我们在javascript中也会定义各种各样的对象。

比如上面描述的Toast插件,我们可以在javascript中定义一个对应的对象,如下:

var Toast = {

	makeTextShort : function(text) {

		return exec("Toast", "makeTextShort", JSON.stringify(text));
	},
	makeTextLong : function(text) {

		return exec("Toast", "makeTextLong", JSON.stringify(text));
	}

}

这里,我们可以看到Toast的makeTextShort方法,会调用上一篇文章中讲到的exec方法,因为弹窗显示这种东西肯定是同步的,不会说做了一会流程,突然间就跑出一个框来,告诉我,你刚才做错了,对吧。

而在这里,我们就会将服务名(Toast),操作方法(makeTextShort),还有显示的内容(JSON.stringfy(text))等通过exec方法,然后利用WebChromeClient的onJsPrompt方法,将命令传递给PluginManager,由PluginManager来处理。

		public boolean onJsPrompt(WebView view, String url, String message,
				String defaultValue, JsPromptResult result) {
		
			System.out.println("onJsPrompt:defaultValue:" + defaultValue + "|" + url + "," + message);
			JSONObject args = null;
			JSONObject head = null;
			try {
				// message:{"service" : "XX", "action" : "xx"}
				head = new JSONObject(message);
				if (defaultValue != null && !defaultValue.equals("")) {
					try {
						args = new JSONObject(defaultValue);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}

				String execResult = mPluginManager.exec(head.getString(IPlugin.SERVICE),
						head.getString(IPlugin.ACTION), args);

				result.confirm(execResult);
				return true;

4)我们会把这些定义的插件对象,还有同步(exec),异步执行(exec_sync)的方法都写到一个javascript文件中,方便统一管理,所以一般这个文件内容就会像下面这样:

var Toast = {
	makeTextShort : function(text) {

		return exec("Toast", "makeTextShort", JSON.stringify(text));
	},
	makeTextLong : function(text) {

		return exec("Toast", "makeTextLong", JSON.stringify(text));
	}
}
var Dialog = {
    ...
}
var AndroidHtml5 = {
	....
	/*
	 * exec_asyn调用的方法 @params {JSONObject} cmd 服务名和动作命令 @params {String} args 参数
	 */
	callNative : function(cmd, args, success, fail) {
		....
	},
<span style="white-space:pre">	</span>...
	callBackJs : function(result,key) {
		...
	}
};

/*
 * Html5与Android同步交互接口
 */
var exec = function(service, action, args) {
	var json = {
		"service" : service,
		"action" : action
	};
	var result_str = prompt(JSON.stringify(json), args);

	var result;
	try {
		result = JSON.parse(result_str);
	} catch (e) {
		console.error(e.message);
	}
	...
}
/*
 * Html5与Android异步交互接口
 */
var exec_asyn = function(service, action, args, success, fail) {
	var json = {
		"service" : service,
		"action" : action
	};
		
	var result = AndroidHtml5.callNative(json, args, success, fail);	

}

结束。





WebView混合开发实战:架构设计、性能优化与疑难排查 混合应用开发通过结合原生应用与Web技术的优势,在移动开发领域提供了一种平衡开发效率与用户体验的解决方案。其核心原理在于利用WebView组件作为容器,加载由HTML、CSS和JavaScript构建的Web内容,并通过JavaScript桥接(JS Bridge)实现与原生系统功能的通信。这种架构的技术价值在于能够复用Web开发技能、实现跨平台部署并支持动态更新,广泛应用于内容展示、企业应用和快速原型开发等场景。在工程实践中,开发者常面临WebView性能优化、内存管理以及兼容性等挑战,例如处理andro 阅读详情

相关推荐

Android GUI Agent技术解析:INJECT_EVENTS与虚拟屏幕实战

GUI Agent是一种能在图形界面层实现感知-决策-执行闭环的智能体系统,其核心原理依赖于对操作系统输入事件流的可控干预与UI渲染路径的隔离重构。技术价值体现在突破传统App被动响应范式,支持免API调用的端侧自动化;关键能力包括毫秒级事件注入(INJECT_EVENTS)、跨进程UI投射(虚拟屏幕)及多模态身份识别(如声纹检测)。典型应用场景涵盖电商比价、金融填单、企业知识库助手等需强交互、高稳定、低侵入的AI落地任务。本文聚焦Android平台真实设备上的GUI Agent构建路径,深入剖析事件注入机

weixin_30394981的博客 385

Android控件(webview)

WebView mWebView =(WebView)findViewById(R.id.show_webView); mWebView.loadUrl(Consts.WEB_URL_BAIDU); // WEB_URL_BAIDU =“https://www.baidu.com/” ``` ## 2.WebView的三个基本组件## ### 2.1WebSettings(做各种设置)*...

syp_snowy的博客 1759

Unity Android应用自身重启的完整实现与避坑指南

Android应用重启是移动开发中的基础能力,涉及Activity生命周期管理、Intent启动机制与系统安全限制等核心原理。在Unity引擎中,由于缺乏原生Application.Restart()支持,开发者需深入理解UnityPlayerActivity初始化流程、exported组件声明规则及FLAG_ACTIVITY_CLEAR_TASK/NEW_TASK标志组合逻辑,才能实现无感、稳定、合规的自身重启。该技术对热更新资源刷新、多语言重载、SDK状态重置等产线高频场景具有关键价值,广泛应用于中大型

weixin_38168547的博客 393

Android WebView浏览器组件 用WebView实现加载网页

什么是WebView WebView是Android中UI组件的一种 WebView基于Webkit内核(Chromium) WebView的用处 WebView可以用来展示网页,并且与网页进行交互 加载网页的四种方式 loadUrl(String url) loadUrl(Strig url,Map<String,String> additionalHttpHeaders) loadData(String data,String mimeType,String encoding)

xqiuqiu_的博客 2520

Cordova Android 3.6.4跨平台移动开发框架实战包

本文还有配套的精品资源,点击获取 简介: 是基于 TAR+GZIP 压缩格式的 Cordova 框架 Android 平台归档文件,支持使用 HTML、CSS 和 JavaScript 构建跨平台移动应用。该版本包含核心库 CordovaLib、插件系统支持、WebView 优化及对 Android 原生功能的访问能力,适用于在 Android Studio 或命令行环境中集成与开发。本资源经过验证,适合用于学习 Cordova 的构建流程、插件机制和 Androi

weixin_35755562的博客 1033

从零开始:使用VMOS Pro和Xposed绕过APP环境检测的完整指南

本文详细解析了使用VMOS Pro和Xposed框架绕过APP环境检测的完整技术方案,包括模拟器检测、Root环境检测和Hook框架检测的对抗方法。通过实战案例和代码示例,展示了如何利用Xposed Hook技术拦截检测逻辑,特别针对360加固等保护技术提供了解决方案。

ee345的博客 734

安卓WebView的使用

WebView是Android中的原生UI控件,主要用于在app应用中方便地访问远程网页或本地html资源。同时,WebView也在Android中充当Java代码和JS代码之间交互的桥梁。实际上,也可以将WebView看做一个功能最小化的浏览器。

qq_40364278的博客 1万+

三维视觉智能焊接系统:免示教技术的工业应用实践

本文深入探讨了三维视觉智能焊接系统中免示教技术的工业应用实践。该系统通过三维视觉相机实时扫描工件,自动识别焊缝并生成轨迹,将产线换型时间从数小时缩短至几分钟,显著提升了生产柔性。文章详细解析了其核心硬件、算法及工厂部署流程,并展望了与数字孪生、工艺智能化融合的未来趋势。

weixin_29091105的博客 432

android 最新webview,还在用Android自带的WebView组件?太Out了!

import android.graphics.PixelFormat;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.KeyEvent;import android.view.Menu;import android.view.MenuItem;import a...

weixin_36331058的博客 563

Unity3D 2022版如何一键安装Newtonsoft.Json?最新Package Manager教程

本文详细介绍了在Unity3D 2022及以上版本中,如何通过Package Manager一键安装和配置Newtonsoft.Json(Json.NET)。教程涵盖了从打开Package Manager、搜索并安装正确包源,到验证安装和基础使用的完整流程,旨在帮助开发者以现代化、可靠的方式集成这一强大的JSON处理框架,提升开发效率并规避手动导入的常见问题。

lg888的博客 921

Arduino创意作品实战案例:手把手教你做温控风扇

通过这个实用的arduino创意作品,轻松实现温度感应与风扇自动控制,结合传感器与编程逻辑,打造智能散热系统,是入门者理想的arduino创意作品实践项目。

weixin_42311427的博客 608

android 插件框架机制,【架构拾集】简易的 Android 混合应用框架的插件架构设计...

Posted by:Phodal HuangSept. 10, 2018, 8:51 p.m.在上一篇文章《【架构拾集】WebView 的 JavaScript Bridge 设计》里,我们介绍了 Android、iOS JavaScript Bridge 的一些 相关设计。这篇文章,则针对上一篇文章,做一些相应的插件管理机制相关的补充。该方案基于 Cordova 框架的插件管理方案,做了尽可能的...

weixin_35899659的博客 151

Android音频学习(十四)——加载音频设备

loadHwModule 是 Android 音频系统的核心初始化函数,负责加载音频硬件抽象层(HAL)的模块实现。它建立 AudioPolicyService 与底层硬件的桥梁,将配置文件(audio_policy_config.xml)中的标签<module>定义转化为可操作的硬件对象,加载的是音频硬件模块(HAL实现),每个模块对应一种音频设备类型,以动态库的形式存在,负责与底层音频硬件交互。

miemie2014的博客 1731

android程序 获取flash容量大小,Android用WebView加载flash大文件偶然会出现内存溢出以及蓝色打问号小方块问题的解决方案...

最近一直在做Android系统定制的项目,核心就是在Android系统中加载flash文件实现各种操作。先一步一步来说下整个方案吧,或许正是读者急需知道的思路。1、预装Adobe Flash插件到Adobe官网下载最新的Android Flash插件,拷贝到ROM包编译之后的out目录以下的systerm目录下,该目录是系统应用app,开机就会把插件装好了!2、为Flash插件添加flash文件的...

weixin_42322467的博客 797

光模块MCU开发全解析:从架构原理到固件调试实战

在高速光模块中,MCU并非传统印象里的核心处理器,而是负责数字诊断、闭环控制和协议管理的嵌入式管家。随着800G、1.6T模块的普及,MCU与DSP/SoC的协同、I2C总线通信、ADC采集、APC/TEC控制等低速域任务愈发关键。理解MCU的选型规格、启动流程和固件设计,是保障光模块稳定运行的基础。本文从光模块架构切入,剖析MCU的角色定位,详细拆解I2C从机实现、电芯片配置、校准与升级等工程细节,并结合实际调试经验梳理常见故障与排查思路,为嵌入式工程师提供一份可落地的光模块MCU开发指南。

weixin_29192365的博客 364

Open3D 曲率下采样

曲率下采样是一种基于几何特征的点云处理技术,通过计算每个点的曲率来判断其所在位置的局部表面特征,从而进行选择性保留。曲率的计算通常基于点的法向量和其邻域点的分布。

纵马踏花向自由 841

Android PhoneGap简析

前言 (转自) 上周研究了一下PhoneGap这个技术,主要是对它的API和插件机制的学习,总体来看这种技术还是有一定的市场,特别是对BS为主的开发来讲确实有很多吸引,当然,这种技术也有严重的短板,比如效率和调试。当然这些都是一个概括性的认识,今天打算在仔细的研究一下,把PhoneGap的jar包反编译了一下,在自己的疑问下,借助互联网的帮助,简单的分析了一下PhoneGap的内部实现和依靠

开发简记 7763

Ubuntu\linux,加载mcp2515的驱动,链接mcp2515,mcp2515的这个驱动默认在linux内核中。jetson nao、香橙派、树莓派

3. 其他文章,还要进行驱动编译就比较复杂了(不推荐)1.树莓派+MCP2515+

pvmsmfchcs的博客 1565

android phonegap 交互,Phonegap 插件调用本地流程分析(三)

PluginManager分析在前面(http://my.oschina.net/lifj/blog/346982),我们知道pluginManager是在CordovaWebView的构造方法中初始化的: 那么我们在CordovaWebView中看看是怎么用这个plugunManager的。在loadUri的方法中,看到这么一段: 对pluginManager做了初始化: 主要也就3步:1....

weixin_33846982的博客 199

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Convex 组件(Component)结构规范与 Node10 模块解析兼容:深入解析 @convex-dev/ratelimiter 测试组件

Convex 组件(Components)是 Convex 中可复用的、带命名空间资源(表、函数、HTTP 路由、环境变量)的部署单元。本文以仓库内 [npm-packages/components/ratelimiter/README.md](https://link.gitcode.com/i/d255eb4574b50935feaa035adcbcc47e) 这份组件结构规范说明为骨架,结合

gitblog_00357的博客 214

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Android百问

1、activity的启动流程? https://blog.youkuaiyun.com/u012267215/article/details/91406211 2、activity的生命周期相关问题 https://mp.weixin.qq.com/s/vS8ldT0r_ZKnlca5a1R00Q 3、系统的启动流程? 4、Jvm虚拟机 5、类加载的过程 6、双亲委派机制 7、JVM,DVM,ART的区别? 8、事件在framework的创建流转过程? 9、SpareArray和HashMap的区别? 10、缓存池的

u013750244的博客 331

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Acode Android代码编辑器:从源码到APK的完整构建指南

在移动设备上进行代码编辑和开发一直是一个技术挑战,如何在资源受限的Android平台上提供功能完整的代码编辑器?Acode项目通过Cordova混合应用架构解决了这一难题,本文将深入解析其构建流程与部署策略。 ## 构建环境配置:解决依赖管理难题 Acode基于现代前端技术栈构建,主要依赖Cordova框架、Webpack打包工具以及TypeScript编译器。项目采用npm作为包管理器,通过

gitblog_00869的博客 316

Flutter 环境搭建与构建排错指南:从安装到混合开发全解析

对于开发者而言,Flutter 的入门门槛往往不在语法,而在环境与工具链的复杂性。从 Flutter 安装与配置、Mac 或 Windows 环境搭建,到 VS Code 中运行项目,每一步都可能遇到网络和依赖版本问题。理解 Flutter SDK、Dart 以及 Gradle 构建链路的运作原理,是高效排查报错的基础。本文从概念出发,解析 Flutter 更新后报错、构建期 Gradle 插件迁移、运行期 Mediacodec 错误等高频问题,并延伸至生命周期、Android 混合开发等工程实践场景。掌握

weixin_34245082的博客 335
上一篇: Android与WebView的同步和异步访问机制
下一篇: 关于字符集的学习笔记
linmiansheng
博客等级 码龄20年 507粉丝 111原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值