移动应用开发的方式:
移动应用开发的方式,目前主要有三种:
- Native App: 本地应用程序;
- Web App:网页应用程序;
- Hybrid App:混合应用程序;
Native App和Web App都有自己的优缺点,而Hybrid App在具备Native App和Web App优点的同时,也继承了两者的缺点。
国内外已经有一些中间件支持混合应用开发,例如:PhoneGap,AppCan,Titanium,Rexsee等,下图可以看到它们之间的一个对比:
混合应用程序实现原理:
在本地应用程序中添加WebView来显示HTML5(CSS、JavaScript)部分的内容,逻辑操作则集中在JavaScript和本地代码中实现。通过JavaScript来实现本地代码和HTML5之间的互操作。这也是上述一些中间件实现的基本原理。
在Android平台上的实现:
首先我们需要一个WebView对象,然后对其属性做一些设置,具体如下:
// 禁止显示垂直条 webView.setVerticalScrollBarEnabled(false); // 允许WebView执行JavaScript webView.getSettings().setJavaScriptEnabled(true); // 自定义JavaScript处理 webView.setWebChromeClient(new CustomWebChromeClient()); // 绑定对象到JavaScript,这样就可以在JS中访问该对象含有的方法 webView.addJavascriptInterface(this, "android"); // 使能DOM存储API webView.getSettings().setDomStorageEnabled(true); // 加载HTML文件 webView.loadUrl("file:///android_asset/game_poker.html");下面给出CustomWebChromeClient的实现:
class CustomWebChromeClient extends WebChromeClient { @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { // 处理Alert显示效果和操作逻辑 AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext()); builder.setTitle("标题"); builder.setMessage(message); builder.setPositiveButton("确定", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { webView.loadUrl("javascript:confirm();"); } }); builder.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { return true; } }); builder.setCancelable(false); AlertDialog dialog = builder.create(); dialog.show(); result.confirm(); return true; } @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { // 处理Confirm显示效果和操作逻辑 return super.onJsConfirm(view, url, message, result); } @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // 处理Prompt显示效果和操作逻辑 return super.onJsPrompt(view, url, message, defaultValue, result); } }如果需要对Alert做不同的UI效果显示和逻辑处理,那么需要在CustomWebChromeClient中做相应处理,最简单的一种方式是可以在onJsAlert中去区别每个显示,而从message中获取这样的标志,可以简单满足这个要求。如果想从message中获取这样的标志,需要事前定义一个协议(协议的复杂程度根据项目需要可以随意定义),例如:::IntegerNumber::,代码中需要查找到“::”包含的内容,并解析得到然后做字符串分割,拿到标志和真正的显示信息即可。当然也有其它方式来完成这样的信息传递,在此不再赘述。
对信息的解析,以下是一种方式:
/** * * @param mixedString 由标志和信息组合的字符串 * @return result[0] : 标志 result[1] : 信息 * @throws Exception */ public String[] getFlagAndMessage(String mixedString) throws Exception { String result[] = new String[2]; Pattern pattern = Pattern.compile("::(.+?)::"); Matcher matcher = pattern.matcher(mixedString); while (matcher.find()) { result[0] = mixedString.substring(matcher.start() + 2, matcher.end() - 2); result[1] = mixedString.substring(matcher.end(), mixedString.length()); } return result; }下面要做的就是根据result[0]来做不同的处理了。
如果WebView所在的Activity含有如下方法:
public String getVersionName() { try { PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_CONFIGURATIONS); return pinfo.versionName; } catch (NameNotFoundException e) { e.printStackTrace(); } return null; }那么我们在JavaScript中的调用可以像下面的格式:
function displayVersionName() { alert(android.getVersionName()); }遇到问题:在从JavaScript中调用Confirm时,返回结果是true或者false,经常根据这个返回结果来做不同操作。当获得返回结果有误时,可以尝试使用WebView调用相应的JavaScript代码来解决。 格式如下:
webView.loadUrl("javascript:function-name(parameters ...);");
如果是费时操作,也可以采用类似方式进行处理来达到想要的效果。
如果你认为这样定制和JS相关的Alert,Confirm,Prompt比较麻烦,而且不通用,那么自定义具有这样功能的显示效果是个不错的选择!:)
在iOS平台上的实现:
和在Android平台上的实现步骤类似,同样也是需要一个WebView对象,并对属性做一些设置,如下:
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"game_poker" ofType:@"html"]; NSURL *url = [NSURL fileURLWithPath:filePath]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request];
如果想定制JavaScript弹出的Alert,Confirm等对话框,可以使用类别来实现,也可以通过Objective-C和JavaScript代码相互调用来实现,而后者也是一些第三方中间件采用的方式。
关键的两个方法:
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
关于这两个方法的具体如何使用,在此不在赘述,网络上有比较多的资料!:)
通过第一个方法来实现从JavaScript中调用,然后可以在Objective-C中对不同类型的请求做操作,通过第二个方法可以实现从Objective-C代码调用JavaScripte代码,从而实现两者的互动。从JavaScript中调用第一个方法,需要设置window.location属性,然后在第一个方法里面对做相应处理:
NSString *mainDocumentURL = [[request mainDocumentURL] relativePath];
但是要注意,window.location的字符长度是有限制的,不要准备过长的字符串,否则会被自动截断。
混合移动应用程序开发时,如果需要对JavaScript弹出的Alert,Confirm做定制,那么最好采用在HTML5+CSS+JavaScript重新定义的形式,而不要在Java和Objective中来做处理,这样可以让JS和本地代码之间的耦合降到最低,从而更方便的在不同平台上做移植。
混合移动应用在响应速度上受到浏览器执行JavaScript速度的影响。
为了控制页面缩放和显示时的宽度,需要在HTML中添加如下代码:
<meta name="viewport" content="user-scalable=no, width=device-width" />
采用上述方法,在Android和iOS上的简单扑克游戏效果如下(只有iOS截图):
更多详细内容,请参考我们公司网站:http://www.anhuioss.com