使用cordova的加强webview
来源:互联网 发布:万得软件下载 编辑:程序博客网 时间:2024/04/29 01:09
demo已经上传git
这种有两种利用方式:
一、集成一个webview来展示工程中的网页,这种稍微简单;
二、集成一个webview来展示服务端的网页,这个稍微有点麻烦,会了这一种前面那种就很容易了。这个其实也有两种方式,一种是将cordova lib编译为arr,在工程中添加依赖库,一种是直接将源码集成进来。因为我有修改源码的需要,所以就直接导入源码了。
这里只说我集成第二种的过程,因为走了不少弯路,记录一下,也帮助下后来人,我集成的cordova版本是4.0.2
1、使用android studio新建一个空工程
2、将前面集成的android工程下的CordovaLib导入进来:
1)file->new->import module,选择对应的目录:
2)导入后,android studio 自动在settings.gradle中添加module:
include ':app', ':CordovaLib'
之后gradle自动sync工程,会报错:
Error:(48, 0) Could not find property 'cdvCompileSdkVersion' on com.android.build.gradle.LibraryExtension_Decorated@5eae5aaa.
这个是因为cordova集成自己的工程添加的属性,直接修改CordovaLib/build.gradle文件:
apply plugin: 'android-library'android { compileSdkVersion 22 buildToolsVersion "22.0.1" sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } }}
这时,工程就已经可以编译了,Lib已经添加成功,下面就是用起来;
3、在主工程中添加cordova lib的依赖:
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' compile project(':CordovaLib')}
4、修改layout文件,添加SystemWebview,这个就是cordova修改过的webview。
<org.apache.cordova.engine.SystemWebView android:id="@+id/cordova_webview" android:layout_width="match_parent" android:layout_height="match_parent"></org.apache.cordova.engine.SystemWebView>
5、在MainActivity中尝试打开外部url:
1)添加权限:
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2)添加cordova的配置文件res/xml/config.xml
<?xml version='1.0' encoding='utf-8'?><widget id="com.example.hello" version="0.0.1"> <preference name="loglevel" value="DEBUG" /> <feature name="myplugin"> <param name="android-package" value="com.example.wangfeng.mycordovawebview.MyCordovaPlugin"/> <param name="onload" value="true"/> </feature></widget>
2)打开url:
LOG.setLogLevel(LOG.DEBUG);//设置日志级别systemWebView = (SystemWebView)findViewById(R.id.cordova_webview);ConfigXmlParser parser = new ConfigXmlParser();parser.parse(this);//这里会解析res/xml/config.xml配置文件CordovaWebView cordovaWebView = new CordovaWebViewImpl(new SystemWebViewEngine(systemWebView));//创建一个cordovawebviewcordovaWebView.init(new CordovaInterfaceImpl(this), parser.getPluginEntries(), parser.getPreferences());//初始化systemWebView.loadUrl("http://www.baidu.com");
结果发现url不能打开,检查网络也没有问题,后来在日志中找到线索:
07-08 08:45:51.998 11874-11894/? W/SystemWebViewClient﹕ URL blocked by whitelist:http://www.baidu.com/
翻了下源码,cordova中对外部网站控制的比较严,用的是白名单的方式,只要不是被允许的,全部拦截。
//SystemWebViewClient.java中,重载了shouldInterceptRequest函数,会进行处理:// Check the against the whitelist and lock out access to the WebView directory// Changing this will cause problems for your applicationif (!parentEngine.pluginManager.shouldAllowRequest(url)) { LOG.w(TAG,"URL blocked by whitelist: " + url); // Results in a 404. return new WebResourceResponse("text/plain", "UTF-8", null);} /** * Called when the webview is going to request an external resource. * * This delegates to the installed plugins, and returns true/false for the * first plugin to provide a non-null result. If no plugins respond, then * the default policy is applied. * * @param url The URL that is being requested. * @return Returns true to allow the resource to load, * false to block the resource. */public boolean shouldAllowRequest(String url) { for (PluginEntry entry : this.entryMap.values()) { CordovaPlugin plugin = pluginMap.get(entry.service); if (plugin != null) { Boolean result = plugin.shouldAllowRequest(url); if (result != null) { return result; } } } // Default policy: if (url.startsWith("blob:") || url.startsWith("data:") || url.startsWith("about:blank")) { return true; } // TalkBack requires this, so allow it by default. if (url.startsWith("https://ssl.gstatic.com/accessibility/javascript/android/")) { return true; } if (url.startsWith("file://")) { //This directory on WebKit/Blink based webviews contains SQLite databases! //DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING! return !url.contains("/app_webview/"); } return false;}
这时,我在上面config.xml中添加的插件MyCordovaPlugin就有用了,看上面源码,只要任何一个plugin允许外部连接,就可以访问,所以我们可以添加自己的规则,我这里只是演示用,全部允许:
public class MyCordovaPlugin extends CordovaPlugin { @Override public Boolean shouldAllowRequest(String url) { return true; }}
此时,外部连接已经可以打开:
但是二级连接还是不能访问:
07-08 08:58:10.406 22771-22771/com.example.wangfeng.mycordovawebview W/CordovaWebViewImpl﹕ Blocked (possibly sub-frame) navigation to non-allowed URL:http://map.baidu.com/mobile/webapp/place/hotelzt/ldata=%7B%22src_from%22%3A%22webapp_wise_home%22%7D
还是去查看源码:
//SystemWebViewClient.java重载了shouldOverrideUrlLoading@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { return parentEngine.client.onNavigationAttempt(url); } //CordovaWebViewImpl.java@Overridepublic boolean onNavigationAttempt(String url) { // Give plugins the chance to handle the url if (pluginManager.onOverrideUrlLoading(url)) { return true; } else if (pluginManager.shouldAllowNavigation(url)) { return false; } else if (pluginManager.shouldOpenExternalUrl(url)) { showWebPage(url, true,false, null); return true; } LOG.w(TAG,"Blocked (possibly sub-frame) navigation to non-allowed URL: " + url); return true;}
我们有好几个方式可以允许操作:
onOverrideUrlLoading这个函数说明我们是否要自己处理这个url,返回true则webview不再处理
shouldAllowNavigation这个函数说明是否允许这种导航,302等跳转包含在内,返回true则webview直接跳转
shouldOpenExternalUrl这个函数说明是否调用外部浏览器打开
我重载了shouldAllowNavigation这个函数,同样的,我们可以在这里定义自己的规则,我这里是全部允许:
@Overridepublic boolean shouldAllowNavigation(String url) { return true;}
当然,我们也可以重载SystemWebViewClient的shouldOverrideUrlLoading函数。
好了,现在我们的webview已经可以打开网页,也可以进入二级页面,甚至cordova帮我们重载了dispatchKeyEvent,在按返回键时,不会退出activity,而是返回历史页面。
6、现在要实现最后一步,执行服务器端的cordova js代码。cordova存在的意义,就在于将js和原生页面结合起来,进行交互。
写了一个test.html,来执行和cordova的plugin交互:cordova.js这个文件就在我们之前自动创建的cordova android工程中
<script type="text/javascript"src="cordova.js"></script><script> showToast = function(msg, callback) { cordova.exec(function(winParam) { callback && callback(null, winParam); }, function(error) { callback && callback(error); }, "myplugin", "toast", [msg]); }; document.addEventListener('deviceready',function(){ showToast("这是一个测试!") }, false);//放在deviceready事件中调用,要不cordova对象可能还没加载完</script>
myplugin就是我们在config.xml中给MyCordovaPlugin起得名字,在其中添加交互的代码:
结果给报了个错:
07-08 09:34:05.954 22669-22669/com.example.wangfeng.mycordovawebview D/CordovaBridge﹕ Ignoring exec() from previous page load
还是翻源码,发现在初始化cordova时,会设定是否允许外部网站进行这种交互:
初始化发生在:
cordova.jsandroidExec.init = function() { bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode); channel.onNativeReady.fire();}; SystemWebChromeClient.java重载onJsPromptString handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue); CordovaBridge.java:promptOnJsPrompt这里,会根据defaultValue来进行初始化操作:else if (defaultValue != null && defaultValue.startsWith("gap_init:")) { // Protect against random iframes being able to talk through the bridge. // Trust only pages which the app would have been allowed to navigate to anyway. if (pluginManager.shouldAllowBridgeAccess(origin)) { // Enable the bridge int bridgeMode = Integer.parseInt(defaultValue.substring(9)); jsMessageQueue.setBridgeMode(bridgeMode); // Tell JS the bridge secret. int secret = generateBridgeSecret(); return ""+secret; } else { Log.e(LOG_TAG,"gap_init called from restricted origin: " + origin); } return "";}
这里会根据shouldAllowBridgeAccess的返回值,来设定bridge的模式,这个函数也会轮询plugin的同名函数,所以还是和上面一样,可以在plugin中进行重载的:
@Overridepublic Boolean shouldAllowBridgeAccess(String url) { return true;}
最后终于测试成功,使用服务端的网页和app的原生页面进行了交互!!
- 使用cordova的加强webview
- 使用cordova的加强webview
- cordova webview的使用
- Cordova使用Webview
- Cordova的WebView兼容问题-X5引擎插件
- 使用Cordova来解决HTML5制作的WebView手机不兼容的问题
- [Phonegap+Sencha Touch] 移动开发70 cordova app中使用增强的webview
- Android与H5互调使用cordova的WebView,插件调用,插件编写
- 移动开发:使用桌面chrome调试安卓设备上的chrome和cordova app(webview)
- Cordova IOS 的使用
- Cordova的使用
- Cordova的简单使用
- cordova 的使用
- Cordova+X5(tencent webview)
- [Phonegap+Sencha Touch] 移动开发17 使用桌面chrome调试安卓设备上的chrome和cordova app(webview)
- [Phonegap+Sencha Touch] 移动开发35 让Cordova app使用Chromium内核的WebView(Crosswalk/XWalk)
- 基于cordova实现的webview实现与h5的交互
- cordova工程webview注入本地js库的方法
- Android View与GroupView原理以及其子类描述
- Android调用系统的相机,图库,以及裁剪图片功能。
- LeetCode-Rotate Array-解题报告
- android Unity3D 修改加强
- 演示:win7如何向其他win7计算机发送消息
- 使用cordova的加强webview
- php中错误和异常处理的机制二(错误处理器和错误触发器)
- vmware安装CentOS6.4详细步骤
- C++ 之RTTI
- Win7下无法安装VS2010旗舰版中VC9.0Runtime组件和.NET Framework 4.0组件
- 【ffmpeg】 音频转换命令
- Redis的安装与使用
- [Err] 1449 - The user specified as a definer ('admin'@'%') does not exist
- WPF 绑定实例之 LISTBOX显示 图片列表