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

利用C#开发移动跨平台Hybrid App(一):从Native端聊Hybrid的实现

2015-11-20 07:51 736 查看

0x00 前言

前一段时间分别读了两篇博客,分别是叶小钗兄的《浅谈Hybrid技术的设计与实现》以及徐磊哥的《从技术经理的角度算一算,如何可以多快好省的做个app》。受到了很多启发,同时也有自己的一些看法。因为目前三大平台(虽然wp的份额相对于iOS以及android来说十分可怜)的开发语言分别是Objective-C(swift)、Java以及C#,先不论平台的其他特性如何,单单是各个平台开发语言就已经不同了。而往往一个App要同时登陆不同的多个平台,那么如何能够快速的开发跨平台的App,尽量使得代码复用便成了一个开发者不得不面对的问题。

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
//开启js支持
webSettings.setJavaScriptEnabled(true);
myWebView.loadData("<html><head><script language = 'JavaScript'>function msg(text){alert(text);}</script></head><body><button type='button' onclick= 'msg()'>web button</button></body></html>", "text/html", "utf-8");

evaluateJavascript(myWebView);
}

....
//Native调用JS
public static void evaluateJavascript(WebView mWebview) {
//判断版本调用不同的方法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
mWebview.evaluateJavascript("msg('native call js')", null);
} else {
mWebview.loadUrl("msg('native call js')");
}
}


View Code

0x03 Web调用Native

Hybrid交互设计

我想行文至此,各位应该已经明白了两大平台(iOS和Android)的Native端是如何调用JS代码的了。那么本小节则主要来聊一聊Web是如何调用Native的。Web和Native之间交互的第一步便是要约定好格式。由于我直接使用了叶小钗兄的Web部分,因此按照他设计的Web请求Native的模型:

requestHybrid({
//创建一个新的webview对话框窗口
tagname: 'hybridapi',
//请求参数,会被Native使用
param: {},
//Native处理成功后回调前端的方法
callback: function (data) {
}
});

//index.html中的实际例子
requestHybrid({
tagname: 'forward',
param: {
topage: 'webapp/flight/index',
type: 'webview'
}
});


而Native端会收到一个URL,例如:

hybrid://forward?t=1447949881120¶m=%7B%22topage%22%3A%22webapp%2Fflight%2Findex%22%2C%22type%22%3A%22webview%22%7D
十分清楚,这里我们交互使用的schema是hybrid://,在Native部分会监控Webview发出的所有schema://请求,然后分发到“控制器”hybridapi处理程序,Native控制器处理时会需要param提供的参数。下面就让我们来分别看一下iOS和Android是如何使用Web调用Native的吧。(这里我只是简单的实现了和叶小钗兄web交互的iOS部分,Android部分演示的是一个简单的Web调用Native的例子)。

iOS Web调用Native

在iOS平台,我们会用到shoudStartLoadWithRequest这个方法来捕获Web所发出的请求。下面我们就来看一段简单的演示吧。

//按照和web端规定的格式,获取数据
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL * url = [request URL];
if ([[url scheme] isEqualToString:@"hybrid"]) {
NSString *actionType = request.URL.host;
//从url中获取web传来的参数
NSDictionary *actionDict = [self getDicFromUrl : url];
//根据web的指示,native端相应的做出回应
[self doActionType:actionType : actionDict];
return NO;
}
return YES;
}

//从url中获取web传来的参数
- (NSDictionary *) getDicFromUrl : (NSURL *)url{
NSArray* paramArray = [[url query] componentsSeparatedByString:@"param="];
NSString* paramStr = paramArray[1];
NSString *jsonDictString = [paramStr stringByRemovingPercentEncoding];
NSData *jsonData = [jsonDictString dataUsingEncoding:NSUTF8StringEncoding];
NSError *e;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:nil error:&e];
return dict;
}

//根据web的指示,native端相应的做出回应
-(void) doActionType : (NSString*) type : (NSDictionary*) dict{

if ([type isEqualToString:@"forward"]) {
[webView goForward];
}
//打开一个新的Web
if([dict[@"type"] isEqualToString: @"webview"]){
[self web2Web: dict[@"topage"]];
}
//打开一个Native页面(我简化为了控件)
else if ([dict[@"type"] isEqualToString: @"native"]){
[self web2Native];
}
}




最左边的图是最开始的Web页面,点击“新开webview...”按钮之后,Native端又打开了一个新的Web页面,即中间的图所示。

最右边的图演示的是点击“跳转native...”按钮之后,Native端创建了一个Native的UI控件。

Android Web调用Native

Android平台上Web调用Native要比iOS稍微复杂一些。因为在Android平台上我们需要借助JavaScriptInterface来实现Web调用Native的功能。

下面就让我们演示一个小例子,不让Web调用JS的alert,相反使用Web调用Native的Dialog来显示提示吧。

首先我们要在Android应用中引入JavaScriptInterface。

...
...
import android.webkit.JavascriptInterface;

public class WebAppInterface {
Context mContext;

WebAppInterface(Context c) {
mContext = c;
}

@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}


之后,我们使用WebView的 addJavascriptInterface()方法将这个类和JS代码绑定,作为Web调用Native的桥梁。

WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");


最后,在Web端也做相应的实现。点击Web中的button会调用Native的showToast方法。

<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />

<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>


0x04 让Web的归Web,Native的归Native

到此,在没有使用C#作为开发语言的两大平台上使用Hybrid的方式令Web和Native交互的内容就介绍完了。但是,不知道各位读者是否和我有相同的感觉呢?那就web和native之间的界线仍然十分明显。

事实上我认为Hybrid的最大价值其实并不在于跨平台。相反,在一些常常变动的模块的热更新的问题上使用这种将Web和Native结合的Hybrid方式是十分适合的。

这是因为它并没有从本质上解决所谓的跨平台的问题,而是采用了一个十分讨巧的方式或者说是逃避问题的方式超脱于平台的范畴。而这也导致了Hybrid的缺点,比如Hybrid体验和Native相比是有距离的。因此,Hybrid是一种优秀的热更新技术,同时也是一个不完美的跨平台方案。

至于解决跨平台问题更好的方案,就交给Native端自己去想办法吧。比如三大移动平台都使用同一种语言甚至是同一个IDE进行Native部分的开发,看上去似乎就是一个很美妙的方案。如果再加上利用Hybrid方式带来的热更新加持,结果就更棒了。

所以,就让Web的归Web,Native的归Native吧。

未完待续~~~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: