如果我们目前的项目是Android的,但是接下来我们希望部分页面可以使用Flutter进行开发,甚至我们希望在Native页面中嵌入FlutterUI组件,那么我们该如何实现呢?
成都创新互联公司"三网合一"的企业建站思路。企业可建设拥有电脑版、微信版、手机版的企业网站。实现跨屏营销,产品发布一步更新,电脑网络+移动网络一网打尽,满足企业的营销需求!成都创新互联公司具备承接各种类型的成都网站制作、做网站项目的能力。经过十多年的努力的开拓,为不同行业的企事业单位提供了优质的服务,并获得了客户的一致好评。
假设你现在Android项目的目录的结构是这样的
这时候如果你想创建一个Flutter模块,使得Android模块和Flutter模块之间可以进行交互,我们可以通过Android Studio新建一个Flutter Module,具体过程是:File — New — New Module ,之后选择Flutter Module,指定Project Location的路径为
也就是说,最终你的项目结构会是这样的
接下来在Android Module的 build.gradle 文件中添加flutter依赖
先创建一个Flutter页面
这里比较重要的是 window.defaultRouteName 这个字段,这个字段可以接收从Native传递过来的参数 (下文我们会介绍原生传递参数的方法),也就是说通过这个字段我们就可以进行Flutter页面的路由的分发
我们可以直接在Android的 MainActivity 中启动一个 FlutterActivity ,这里的 initialRoute 方法中传递的参数就对应Flutter层的 window.defaultRouteName
注意:需要在 AndroidManifest.xml 注册 FlutterActivity
自己创建一个 FlutterAppActivity 继承自 FlutterActivity
在 MainActivity 中启动 FlutterAppActivity (另外别忘了在 AndroidManifest.xml 中注册 FlutterAppActivity )
两种启动方式的区别
如果单纯只是想打开一个Flutter页面,两种方式实际上基本没有太大区别,第一种方式也许还会更简单一点。但是,在Flutter开发中,我们往往还需要开发一些Native插件供Flutter调用,如果使用复写 FlutterActivity 的方式更有利于我们在 FlutterActivity 中注册我们的Native插件,所以实际开发中一般推荐使用第二种方式
扩展思考
initialRoute 从名称上看起来是Flutter提供给我们进行Native与Flutter交互的路由跳转的,但是实际上他就是一个字符串,我们不仅仅可以传递一个路由名称,有时候我们也可以通过这个参数传递一串JSON数据,然后在Flutter端进行解析,这样我们就可以通过这个参数做更多的事情
activity_main.xml
FrameLayout 用于承载Flutter组件
MainActivity.java
使用 FragmentManager 将 FlutterFragment 添加到 FrameLayout 容器中
运行结果
上半部分是原生的TextView,下半部分是Flutter的Text组件
本节主要介绍了Native和Flutter之间的页面跳转,以及同一个页面中Native与Flutter组件的组合。接下来会介绍如何编写Android插件与Flutter进行数据交互
Cordova是一个广泛使用的Hybrid开发框架,它提供了一套js和Native交互规范
在Cordova的SystemWebViewEngine类中可以
看到私有静态void exposeJsInterface(WebView webView,CordovaBridge桥){
if((Build.VERSION.SDK_INT Build.VERSION_CODES.JELLY_BEAN_MR1)){
Log.i(TAG,“自Android版本以来已禁用addJavascriptInterface()桥接。”);
//错误是Java Strings不会自动转换为JS字符串。
//在JS方面解决这个问题并不困难,但是更容易
使用提示桥来代替。
返回;
}
webView.addJavascriptInterface(新SystemExposedJsApi(桥), “_cordovaNative”);
}
因此当Android系统高于4.2时,Cordova还是使用addJavascriptInterface这种方式,因为这个方法在高版本上安全而且简单,低于4.2的时候,用什么方法呢?
答案是WebChromeClient.onJsPrompt方法
WebView可以设置一个WebChromeClient对象,它可以处理js的3个方法
onJsAlert
onJsConfirm
onJsPrompt
这3个方法分别对应js的警告,确认,提示方法,因为只有提示接收返回值,所以js调用一个Native方法后可以等待Native返回一个参数。下面是cordova.js中的一段代码:
/ **
*实现ExposedJsApi.java的API,但使用prompt()进行通信。
*这是在JellyBean之前使用的,其中addJavascriptInterface()被禁用。
* /
module.exports = {
exec:function(bridgeSecret,service,action,callbackId,argsJson){
return prompt(argsJson,'gap:'+ JSON.stringify([bridgeSecret,service,action,callbackId]));
},
setNativeToJsBridgeMode:function(bridgeSecret,value){
prompt(value,'gap_bridge_mode:'+ bridgeSecret);
},
retrieveJsMessages:function(bridgeSecret,fromOnlineEvent){
return prompt(+ fromOnlineEvent,'gap_poll:'+ bridgeSecret);
}
};
然后只要在onJsPrompt方法中使用CordovaBridge来处理js的提示调用
/ **
*告诉客户端向用户显示提示对话框。如果客户端返回true,则WebView将假定客户端将处理提示对话框并调用相应的JsPromptResult方法。
* p /
*由于我们出于自己的目的黑客提示,我们不应该为此目的使用它们,也许我们应该破解console.log来代替!
* /
@Override
public boolean onJsPrompt(WebView视图,String origin,String message,String defaultValue,final JsPromptResult result){
//与@JavascriptInterface桥不同,此方法始终在UI线程上调用。
String processedRet = parentEngine.bridge.promptOnJsPrompt(origin,message,defaultValue);
if(processedRet!= null){
result.confirm(processedRet);
} else {
dialogsHelper.showPrompt(message,defaultValue,new CordovaDialogsHelper.Result(){
@
Override public void gotResult(boolean success,String value){
if(success){
result.confirm(value);
} else {
result.cancel( );
}
}
});
}
return true;
}
混合开发的App(Hybrid App)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html 5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更好又可以节省开发的资源。
一、Adobe Edge
目前还处于预览阶段的Adobe
Edge是用HTML5、CSS、JavaScript开发动态互动内容的设计工具。内容可以同时兼容移动设备和桌面电脑。Edge的一个重要功能是
Web工具包界面,方便确保页面在不同浏览器中的架构一致性,此外Edge还将整合TypeKit这样的字体服务。
动画和图形可以添
加到HTML元素中,程序也能通过Edge自身的代码片段库或者JavaScript代码进行扩展。动画可以在独立的时间线上进行嵌套,还能实现互动功
能。符合可以服用并通过API和代码片段控制。通过Edge设计的内容可以兼容iOS和Android设备,也可以运行在火狐、Chrome、
Safari和IE9等主流浏览器。
二、Adobe Dreamweaver CS6
Adobe
Dreamweaver CS6作为一个Web设计软件,提供了对HTML网站和移动程序的可视化编辑界面。其Fluid
Grid排版系统整合CSS样式表功能,提供自适应版面的跨平台兼容性。开发者可以完全实现Web设计的可视化操作,无需为代码所困。
用户不但还能在Live View中预览,还提供多屏幕预览功能。开发者可以通过MultiScreen预览面板查看HTML5内容的渲染效果。Live View通过WebKit渲染引擎支持HTML5。
三、Adobe ColdFusion 10
ColdFusion是用来开发企业Web程序的服务器端技术,通过Websockets、互动表单、视频和地理标签等HTML5技术创建富媒体用户体验。
四、Sencha Architect 2
在开发移动和桌面应用的工具中,Sencha的定位是HTML5可视化应用开发。开发团队可以在一个单一集成的环境中完成应用的设计、开发和部署。开发者还可以开发Sencha Touch2和Ext JS4 JavaScript应用,并实时预览。
五、Sencha Touch 2
Sencha Touch2是移动应用框架,也被看作是Sencha的HTML5平台。开发者可以用它开发面向iOS、Android和Blackberry、Kindle Fire等多种平台的移动应用。
六、Dojo Foundation Maqetta
来自于IBM的一个项目,Dojo Foundation Maqetta是为桌面和移动设备开发HTML5应用的开源工具,支持在浏览器中查看HTML5界面。用户体验设计师可以通过拖放组装UI样板
七、微软Visual Studio 2010 ServicePack 1
虽然一开始并不支持HTML5,但微软在2011年三月发布的Visual Studio 2010 SP1中提供了IntelliSense,追加了针对HTML5的一些元素。
八、JetBrains WebStorm 4.0
作为拥有HTML编辑器的JavaScript集成开发环境,WebStorm4.0提供了开发web应用的HTML5样板。开发者可以在创建HTML文档时可获得对HTML5文件的支持。例如砍伐者键入。开发者还可以在chrome浏览器中实时预览HTML文档。
九、Google Web Toolkit
该开发工具用于开发浏览器应用,但库中支持很多HTML5功能。包括对客户端或web存储的支持。其他HTML5功能还包括支持Canvas可视化,以及音频和视频widget。
十、DCloud HBuilder
HBuilder是当前最快的HTML开发工具,强大的代码助手帮你快速完成开发,最全的语法库和浏览器兼容性数据让浏览器碎片化不再头痛。
Cordova是一个广泛使用的Hybrid开发框架,它提供了一套js和Native交互规范
在Cordova的 SystemWebViewEngine 类中可以看到
private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
if ((Build.VERSION.SDK_INT Build.VERSION_CODES.JELLY_BEAN_MR1)) {
Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
// Bug being that Java Strings do not get converted to JS strings automatically.
// This isn't hard to work-around on the JS side, but it's easier to just
// use the prompt bridge instead.
return;
}
webView.addJavascriptInterface(new SystemExposedJsApi(bridge), "_cordovaNative");
}
因此当Android系统高于4.2时,Cordova还是使用 addJavascriptInterface 这种方式,因为这个方法在高版本上安全而且简单,低于4.2的时候,用什么方法呢?
答案是 WebChromeClient.onJsPrompt 方法
WebView可以设置一个 WebChromeClient 对象,它可以处理js的3个方法
onJsAlert
onJsConfirm
onJsPrompt
这3个方法分别对应js的 alert 、 confirm 、 prompt 方法,因为只有 prompt 接收返回值,所以js调用一个Native方法后可以等待Native返回一个参数。下面是 cordova.js 中的一段代码:
/**
* Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
* This is used pre-JellyBean, where addJavascriptInterface() is disabled.
*/
module.exports = {
exec: function(bridgeSecret, service, action, callbackId, argsJson) {
return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId]));
},
setNativeToJsBridgeMode: function(bridgeSecret, value) {
prompt(value, 'gap_bridge_mode:' + bridgeSecret);
},
retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) {
return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret);
}
};
然后只要在 onJsPrompt 方法中使用 CordovaBridge 来处理js的prompt调用
/**
* Tell the client to display a prompt dialog to the user. If the client returns true, WebView will assume that the client will handle the prompt dialog and call the appropriate JsPromptResult method.
* p/
* Since we are hacking prompts for our own purposes, we should not be using them for this purpose, perhaps we should hack console.log to do this instead!
*/
@Override
public boolean onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result) {
// Unlike the @JavascriptInterface bridge, this method is always called on the UI thread.
String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);
if (handledRet != null) {
result.confirm(handledRet);
} else {
dialogsHelper.showPrompt(message, defaultValue, new CordovaDialogsHelper.Result() {
@Override
public void gotResult(boolean success, String value) {
if (success) {
result.confirm(value);
} else {
result.cancel();
}
}
});
}
return true;
}