Hybrid App
(混合模式移动应用)开发是指介于Web-App
、Native-App
这两者之间的一种开发模式,兼具Native App
良好用户交互体验优势和Web App
跨平台开发优势,技术上主要以webview和javascript的相互调用实现。
移动应用开发的四种方式
- Native App: 原生应用(原生App)
- React Native:React原生应用
- Hybrid App:混合应用(混合App)
- Web App:网页应用(移动Web)
Native App | React Native | Hybrid App | Web App | |
开发成本 | 高 | 中 | 中 | 低 |
开发语言 | Native语言 | Web语言 | Web语言 | Web语言 |
安装更新 | 复杂 | 简单 | 简单 | 简单 |
跨平台 | 差 | 优 | 优 | 优 |
设备访问 | 高 | 中 | 中 | 差 |
高级图形 | 高 | 中 | 中 | 中 |
体验 | 优 | 良 | 良 | 差 |
Native与H5交互原理
移动端网页运行在手机应用内嵌的浏览器引擎中,这个没有UI的内核容器统称WebView,即iPhone的UIWebView(iOS 2.0–12.0)、WKWebView(iOS 8.0+,macOS 10.10+)和Android的WebView。也就是说,WebView就是在手机应用中运行和展示网页的界面和接口。
iOS与JS交互的解决方案
JavaScriptCore iOS 7.0+ macOS 10.5+ Mac Catalyst 13.0+Beta tvOS 9.0+
JavaScriptCore
是苹果Safari浏览器的JavaScript引擎,就跟Google的V8引擎一样用来解析 JavaScript 代码,苹果在iOS7引入了JavaScriptCore框架,使得Objective-C 和 JavaScript 代码直接的交互变得更加的简单方便。
oc与js类型对照:
Objective-C type | JavaScript type |
nil | undefined |
NSNull | null |
NSString | string |
NSNumber | number, boolean |
NSDictionary | Object |
NSArray | Array |
NSDate | Date |
NSBlock | Function |
id | Wrapper |
Class | Constructor |
Objective-C代码:
// 创建一个JSContext上下文对象,类似于JS中的Window对象
JSContext *ctx = [[JSContext alloc] init];
//定义js异常处理器
ctx.exceptionHandler = ^(JSContext *context, JSValue *exception){
// 当执行js出现异常时会在控制台上打印
NSLog(@"js异常:%@",exception);
};
// 执行JS代码
[ctx evaluateScript:@"var num = 10"];
[ctx evaluateScript:@"var arr = ['a', 'b', 'c']"];
[ctx evaluateScript:@"var foo = function(num) {return Math.pow(num, 2);}"];
// 获取js变量num
JSValue *num = ctx [@"num"];
// 获取数组中第一个参数
JSValue *arr = ctx[@"arr"];
JSValue *arr1= arr[0];
// 获取num值的平方
JSValue *square = [ctx evaluateScript:@"foo(num)"];
// oc调用js nativeInvokeJS被定义在H5页面中
JSValue * nativeInvokeJS = ctx[@"nativeInvokeJS"];
// 调用了js中方法"nativeInvokeJS",并且传参数@"hello word"
[nativeInvokeJS callWithArguments:@[@"hello word"]];
// 生成本地js方法,供h5调用
ctx[@"jsInvokeNative"] = ^(NSString *paramer){
JSValue *currentThis = [JSContext currentThis];\
JSValue *currentCallee = [JSContext currentCallee];
NSArray *currentParamers = [JSContext currentArguments];
dispatch_async(dispatch_get_main_queue(), ^{
// js调起OC代码,代码在子线程,更新OC中的UI,需要回到主线程
NSLog(@"js参数:%@",paramer);
});
HTML5代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>H5与Native交互</title>
</head>
<body>
<script>
var nativeInvokeJS = function(parameter) {
alert (parameter);
};
</script>
<button onclick="jsInvokeNative('js')">调用OC方法</button>
</body>
</html>
上面两段代码就是通过JavaScriptCore实现的Objective-C 和 JavaScript的简单交互示例。
WebViewJavascriptBridge
WebViewJavaScriptBridge用于WKWebView和UIWebView 中 OC 和 JS 交互的一个 iOS/OSX 桥接层。
Objective-C代码:
#import "WebViewJavascriptBridge.h"
@property WebViewJavascriptBridge* bridge;
// 使用wkwebview、uiwebview(ios)或webview(osx)实例化一个webviewjavascriptbridge对象
self.bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
[self.bridge registerHandler:@"ObjC Echo" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"ObjC Echo called with: %@", data);
responseCallback(data);
}];
[self.bridge callHandler:@"JS Echo" data:nil responseCallback:^(id responseData) {
NSLog(@"ObjC received response: %@", responseData);
}];
HTML5代码:
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'https://__bridge_loaded__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
// 注册 OC handlers & 调用OC handlers
setupWebViewJavascriptBridge(function(bridge) {
/* Initialize your app here */
bridge.registerHandler('JS Echo', function(data, responseCallback) {
console.log("JS Echo called with:", data)
responseCallback(data)
})
bridge.callHandler('ObjC Echo', {'key':'value'}, function responseCallback(responseData) {
console.log("JS received response:", responseData)
})
})
WKWebView iOS 8.0+ macOS 10.10+
从iOS 8.0和OS X 10.10开始,使用WKWebView将Web内容添加到应用程序中。不再使用UIWebview或webview。
UIWebView iOS 2.0–12.0 Deprecated
Android与JS交互的解决方案
Android调用H5
在 Kitkat(4.4)之前并没有提供 iOS 类似的调用方式,只能用 loadUrl 一段 JavaScript 代码,来实现:
// 调用js中的JSBridge.trigger方法
webView.loadUrl("javascript:JSBridge.trigger('nativeInvokeJs')");
而在 Kitkat 之后的版本,也可以用 evaluateJavascript 方法实现:
webView.evaluateJavascript("javascript:nativeInvokeJs()", new ValueCallback<String>() {
@Override
publicvoidonReceiveValue(String value){
}
});
H5调用Android
- 拦截 URL SCHEME
- webview中注入API
// 注入API
class JSInterface {
@JavascriptInterface
public String jsInvokeNative(params) {
return params;
}
}
webView.addJavascriptInterface(new JSInterface(), "JSBridge");
HTML5代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>H5与Native交互</title>
</head>
<body>
<script>
var nativeInvokeJS = function(parameter) {
alert (parameter);
};
</script>
<button onclick="JSBridge.jsInvokeNative('js')">调用Native方法</button>
</body>
</html>
这篇文章目前没有评论