您的位置:首页 > 移动开发

安卓混合开发之Cordova,NativeWebView两种实现

2015-11-06 15:38 645 查看

转载请注明出处:王亟亟的大牛之路

如今混合开发已经不是新鲜词了,虽然作为源生的死忠我不怎么愿意去用H5实现我的功能,但是需求说了算。。。还是屈服了。。。然后就去了解了下,也抠了点Demo在这里分享给大家(也许网上有类似的,但是我这个肯定是可以run并且实现方式是不同的)

上内容之前,先说下纯H5 混合 纯native的各种区别,不了解的可以看下下面的简单描述(扣来的)



一、原生应用

优点


可访问手机所有功能(GPS、摄像头);

速度更快、性能高、整体用户体验不错;

可线下使用(因为是在跟Web相对地平台上使用的);

支持大量图形和动画;



缺点:


开发成本高;

支持设备非常有限(一般是哪个系统就在哪个平台专属设备上用);

上线时间不确定(审核过程不一);

内容限制(各个应用商店对其有限制);

获得新版本时需重新下载应用更新。



二、Web 应用

优点:


支持设备广泛;

较低的开发成本;

可即时上线;

无内容限制;

用户可以直接使用最新版本(自动更新,不需用户手动更新)。



缺点:


表现略差(对联网的要求比较大);

用户体验没那么炫;

图片和动画支持性不高;

没法在App Store中下载;(苹果爸爸不能忍)

要求联网;

对手机特点有限制(摄像头、GPS等)。



三、混合应用

优点

兼容多平台;
顺利访问手机的多种功能;
App Store中可下载(Wen应用套用原生应用的外壳);
可线下使用。


缺点


不确定上线时间;

用户体验不如本地应用;

性能稍慢(需要连接网络);

技术还不是很成熟。



总结:


比如,你的预算是多少?预算充足的话可以开发几个本地应用加一个Web应用。

你的应用需要什么时候面市?Web应用可以很快地开发然后直接推出来。

你的应用需要包含什么特点和功能?如果跟手机的某些功能深度整合了,比如摄像头,需要呈现大量图形和动画就选原生应用好点



好,以上都是官话,其实作为native的coder给我的感觉就是,为什么都要加载,好蛋疼(可能是优化做得不够),反正肯定没native顺手。

好了不抱怨了,上代码!

首先是native应用套用一个WebView的例子

包目录:



运行效果



补充:当然,这一类型还是以源生的内容为主,业务逻辑啊操作等还是主要在源生这部分,html这边主要做一些展示和简单的数据传递的作用。

就一个Activity

public class MainActivity extends Activity {

private WebView contentWebView = null;
private TextView msgView = null;

@SuppressLint("SetJavaScriptEnabled")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contentWebView = (WebView) findViewById(R.id.webview);
msgView = (TextView) findViewById(R.id.msg);
//启用js
contentWebView.getSettings().setJavaScriptEnabled(true);
contentWebView.addJavascriptInterface(this, "wjj");
//加载HTML
contentWebView.loadUrl("file:///android_asset/wjj.html");

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(btnClickListener);
}

OnClickListener btnClickListener = new OnClickListener() {
public void onClick(View v) {
contentWebView.loadUrl("javascript:javacalljs()");
contentWebView.loadUrl("javascript:javacalljswithargs(" + "'hello world'" + ")");
}
};

@JavascriptInterface
public void startFunction() {
Toast.makeText(this, "js调用java", Toast.LENGTH_SHORT).show();
runOnUiThread(new Runnable() {

@Override
public void run() {
msgView.setText(msgView.getText() + "\njs调用java");

}
});
}

@JavascriptInterface
public void startFunction(final String str) {
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
runOnUiThread(new Runnable() {

@Override
public void run() {
msgView.setText(msgView.getText() + "\njs调用java传递参数" + str);

}
});
}
}


在测试的过程中,发现4.4版本以下和以上对js的支持有一些差异,需要加一个标签,如果不加会有
Uncaught TypeError: Object [object Object] has no method ‘startFunction’;
的一个错误,导致js并没有被执行。

如何去避免呢?

在你的方法前面加上 @JavascriptInterface;

像这样

@JavascriptInterface
public void startFunction() {
Toast.makeText(this, "js调用java", Toast.LENGTH_SHORT).show();
runOnUiThread(new Runnable() {

@Override
public void run() {
msgView.setText(msgView.getText() + "\njs调用java");

}
});
}
记住上面的wjj 在HTML里就是调用那些JS函数的对象


HTML部分的代码:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<script type="text/javascript">
function javacalljs(){
document.getElementById("content").innerHTML +=
"<br\>java调用了js函数";
}

function javacalljswithargs(arg){
document.getElementById("content").innerHTML +=
("<br\>"+arg);
}

</script>
</head>
<body>
this is my html <br/><br>
<button onClick="window.wjj.startFunction()">点击调用java代码</button><br/><br>
<button onClick="window.wjj.startFunction('hello world')" >点击调用java代码并传递参数</button>
<br/>
<div id="content">内容显示</div>
</body>
</html>


就是 这么 EASY 就能两边的交互了,所以以native为主的混合开发 还是比较简便的。

源码地址:https://github.com/ddwhan0123/BlogSample/tree/master/WebViewDemo

接下来是给予Web开发者春天的Cordova ,前身也就是Phonegap(还有其他一些实现,包括国内也有一些盈利的企业在做这方面的事)。

理论性的描述,大家可以看http://www.cnblogs.com/hubcarl/p/4202784.html

我这边只上实现,包结构



要注意的地方已经圈出来了,为什么需要注意,如何搭建这个项目可以参照,讲的很清晰:http://www.adobe.com/cn/devnet/html5/articles/getting-started-with-phonegap-in-eclipse-for-android.html

我这边主要阐述的是两部分如何交互

入口页面(参数也会返回到这里)

public class TestActivity extends Activity {
private EditText edittext;
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
edittext = (EditText) findViewById(R.id.EditText1);
button = (Button) findViewById(R.id.Button1);
// 接收html页面参数
String str = getIntent().getStringExtra("name");
String str1 = getIntent().getStringExtra("pass");
edittext.setText("name:" + str + "  " + "pass:  " + str1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(TestActivity.this,
HomeActivity.class);
startActivity(intent);
}
});
}
}


WebView页面

public class HomeActivity extends DroidGap {
/** Called when the activity is first created. */

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 解决黑屏问题
super.init();
this.appView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
//记住这个wjj字符串,在js终究是以他来调用具体的函数的
this.appView.addJavascriptInterface(new PluginMethod(this, appView), "wjj");
this.appView.setBackgroundResource(R.drawable.login);
//加载动画
super.setIntegerProperty("splashscreen", R.drawable.main_bg);
// 固定页脚
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
super.loadUrl("file:///android_asset/www/index.html", 1500);
}

/* 弹出吐司 */
public void makeToast() {
Toast.makeText(this, "弹出了内容", Toast.LENGTH_SHORT).show();
}

class PluginMethod {
private WebView webView;
private DroidGap droidGap;

public PluginMethod(DroidGap gap, WebView view) {
webView = view;
droidGap = gap;
}

/* native和JS传参 */
public void goToActivity(final String str,final String str1) {
Log.d("goToActivity", " 帐号 "+str+" "+" 密码 "+str1);
Intent intent = new Intent();
intent.putExtra("name", str);
intent.putExtra("pass", str1);
intent.setClass(HomeActivity.this, TestActivity.class);
startActivity(intent);
}

public void makeToast(final String value) {
Toast.makeText(HomeActivity.this, "获取到了"+value, Toast.LENGTH_SHORT).show();
}

public void getvalue(final String value) {
Toast.makeText(HomeActivity.this, "rande获取到了"+value, Toast.LENGTH_SHORT).show();
}
}

}


HTML页面(内容有点多,之前测试兼容性的时候乱加了点东西,主要看js里就行)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PhoneGap</title>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<link rel="stylesheet" type="text/css"
href="css/jquery.mobile-1.3.2.min.css">
<script type="text/javascript" charset="utf-8" src="js/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="js/jquery.mobile-1.3.2.min.js"></script>
</head>
<script type="text/javascript">
$("#page").live("pagecreate",function(){
$("#gotoactivity").click(function() {
window.wjj.goToActivity($("#text1").val(),$("#text2").val());
});

$("#makeToast").click(function() {
window.wjj.makeToast('HelloWorld');
});

$("#getvalue").click(function() {
window.wjj.getvalue(document.getElementById("points").value);
});

});
</script>
<body>
<!-- 页面容器 -->
<div data-role="page" id="page">
<!-- header -->
<div data-role="header" data-position="fixed">
<h1>大标题 很长很长</h1>
</div>
<!-- content部分 -->
<div data-role="content">
<p><h1>你好 打了一长串字</h1></p>
用户名: <input type="text" id="text1" placeholder="输入内容" />
密   码:<input type="text" id="text2" placeholder="输入内容" />

<a id="gotoactivity" data-role="button">跳转到activity</a>

<a id="makeToast" data-role="button" >制造吐司传一个helloworld</a>

<a href="https://www.baidu.com/" data-role="button">外部链接</a>

<a data-icon="home" data-role="button">主页图标按钮</a>

<br>

<div data-role="controlgroup" data-type="horizontal">
<a data-role="button">aa</a>
<a data-role="button">bb</a>
<a data-role="button">cc</a>
<a data-role="button">dd</a>
</div

<!-- MP3播放部分 -->
<audio controls>
<source src="vedio/horse.mp3" type="audio/mpeg">
<source src="horse.ogg" type="audio/ogg">
</audio>

<input type="range" id="points" value="15" min="0" max="100" data-show-value="true">

<a id="getvalue" data-role="button">获取滑动的参数</a>

</div>
<!-- footer部分 -->
<div data-role="footer"  data-position="fixed">
<h4>脚注</h4>
</div>
</div>

</body>
</html>


还有一种实现是需要配置xml的我还是比较推荐这种实现的。

源码地址:https://github.com/ddwhan0123/BlogSample/tree/master/PhoneGap2



观众老爷们点个赞啊!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: