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

SageMath下载与安装

SageMath的下载与安装

旺旺的碎冰冰~的博客 7495

安卓WebView的使用

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

qq_40364278的博客 1万+

《UE4游戏开发》之 《音效系统的实现》

音效系统需要负责管理什么事情: 1.1 确定声音控制的分类:如背景音乐、技能音效、界面音效、角色配音等,不同游戏对声音有不同的分类 1.2 控制每个分类的声音的开启与关闭,以及调节每个分类声音的大小 解决如何分类: 2.1 首先需要知道ue4为声音分类提供了什么:SoundClass通常需要一个根分类【SC_RPG_Master】,便于总体控制音效,以及指定引擎默认启动的音效 打开SoundClass资产【SC_RPG_Master】,对根控制的设置,将逐级传递并按比例进行设置,以此达到控制一类声音的目的.

qq_21919621的博客 2126

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

第四节、C# 上位机面向对象编程详解(工控硬件继承实战版)

继承核心价值:在 C# 上位机工控开发中,继承的核心是通用逻辑复用与接口统一,将所有硬件的通用属性 / 方法封装到抽象基类,子类只需实现独有逻辑,大幅减少冗余代码。基类设计要点:优先使用抽象基类,合理分配访问修饰符(privateprotectedpublic),定义通用事件与虚方法,提供资源释放机制,兼顾复用性与扩展性。子类设计要点:通过: base()调用基类构造函数,强制实现抽象方法(保证接口统一),选择性重写虚方法(实现独有逻辑),复用基类的protected成员。多设备管理。

kylezhao2019的博客 787

蛋白质组学实战指南 | (八)从数据到洞见:差异蛋白筛选与功能解析全流程

本文系统阐述了蛋白质组学数据分析中,从原始数据质控到差异蛋白筛选与功能解析的全流程。重点介绍了数据质量评估、差异蛋白筛选的统计方法(包括多重检验校正)、功能注释与富集分析,以及蛋白互作网络构建与关键节点识别。最后,为如何将生物信息学洞见转化为实验验证提供了清晰的规划思路,助力研究者完成从数据到生物学知识的闭环。

weixin_29250573的博客 372

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

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

weixin_35899659的博客 151

如何实现SOLIDWORKS阵列的“智能变更”?

有时,我们在设计一个零件时,零件上有一排阵列孔,同时零件有不同的长度,我们又希望可以做到零件长度改变时,这排孔可以按长度等距增减孔阵列的个数;或是零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那具体要怎么做呢?接下来,我们一起来看看怎么用SOLIDWORKS中简单的操作来实现这两种智能的变更: 零件长度加长或缩短时,这排孔要按长度等距增减孔阵列的个数。 零件长度加长或缩短时,这排孔保持个数不变,按零件长度增减孔距。 那接下来,我们一起来看看怎么用简单的操作来实现这两种智能的

SOLIDWORKS艾金米 2078

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

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

weixin_42322467的博客 797

第44节:cesium 大雾效果(cesium自带)(含源码+视频)

cesium 大雾效果(cesium自带)

qq_29384639的博客 1702

视觉SLAM十四讲slambook2示例代码所有依赖库的编译安装教程(VTK、OpenCV3、ceres、Sophus、g2o、Eigen、Pangolin、googletest等)

这是2021年的最后一篇博客~ 新年快乐! 0 准备工作   首先需要先安装cmake编译器: sudo apt-get install cmake   以及,将十四讲的示例代码克隆下来(十四讲的源码地址点击这里): git clone --recursive https://github.com/gaoxiang12/slambook2.git   由于里面的3rdparty文件夹内所有内容都来自于其他github仓库,所以需要加上--recursive参数,不然克隆下来的内容不完整。   如果你.

zeeq的博客 7839

Android PhoneGap简析

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

开发简记 7763

极智AI | 算能SC5+智算卡驱动安装与升级

大家好,我是极智视界,本文介绍一下 算能SC5+智算卡驱动安装与升级

极智视界 1277

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

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

weixin_33846982的博客 199

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

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

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

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、付费专栏及课程。

余额充值