首先,先列舉幾個常用場景(本人項目實戰(zhàn)中經歷過的):
1.通過js調用native的組件(例如經典的二維碼掃描功能)
2.點擊H5界面調用native的控制器,進行跳轉
3.在native中編寫js代碼維護H5中的內容
以上三個差不多就是我用到過的場景.
下面分別開始介紹交互方式,這里我用的是JavaScirptCore + UIWebView:
1.js調用本地組件
js端代碼:
/*注解:這里采用nativeObj.goSomeWhere()的方式進行跳轉,主要是為了配合安卓端的交互方式(ios和安卓共用一套js代碼),
nativeObj是一個統(tǒng)一的對象,代表原生的內容,通過點語法調用方法跳轉,后面會說到如何產生這個公用的對象*/
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<script type="text/javascript">
//回調支付的結果
function NativePayCallback(result) {
console.log("NativePayCallback------"+result);
document.getElementById("native_info").innerHTML = result.code;
}
//回調登錄結果
function NativeLoginCallback(result) {
console.log("NativeLoginCallback------"+result);
document.getElementById("native_info").innerHTML = result;
}
//回調掃碼結果
function scanBarcodeCallback(result) {
console.log("scanBarcodeCallback------"+result);
document.getElementById("native_info").innerHTML = result;
}
//退后
function goBackNative() {
nativeObj.goBackNative('');
}
//跳轉到支付界面
function goNativePay() {
var jsonObj = {
totalFee:"3.32",
from:"OtherAPP",
orderNum:"xxxxxxxxxx"
};
var jsonStr=JSON.stringify(jsonObj);
nativeObj.goNativePay(jsonStr);
}
//跳轉到登錄頁
function goNativeLogin() {
nativeObj.goNativeLogin('');
}
//跳轉到掃碼頁
function scanBarcode() {
nativeObj.scanBarcode('');
}
//得到用戶信息
function getNativeUserInfo(){
var userInfo=nativeObj.getNativeUserInfo('');
console.log("getNativeUserInfo------"+userInfo);
var obj = JSON.parse(userInfo);
console.log(obj.code + ", " + obj.data+", " + obj.msg);
document.getElementById("native_info").innerHTML = obj.code + ", " + obj.data+", " + obj.msg;
}
</script>
<body>
<input type="button" value="關閉activity" onClick="goBackNative()"/>
<input type="button" value="支付" onClick="goNativePay()"/>
<input type="button" value="登錄" onClick="goNativeLogin()"/>
<input type="button" value="掃二維碼" onClick="scanBarcode()"/>
<input type="button" value="獲取個人信息" onClick="getNativeUserInfo()"/>
<text id="native_info"></text>
</body>
</html>
native原生端代碼,說明一下,如果是采用nativeObj.goSomeWhere的方式進行交互,那么我們需要用到JavaScriptCore中的JSExport協(xié)議(具體用法我不贅述),直接上代碼:
//這里我是自己創(chuàng)建了一個TPNativeFunctionTool的工具類,用于統(tǒng)一處理交互事件,
繼承了JSExport協(xié)議,在協(xié)議中聲明js中的對應方法
@protocol myJSExports <JSExport>
//退后
- (void)goBackNative;
//跳轉支付界面,json是傳遞過來的支付參數(shù)
- (void)goNativePay:(id)json;
//跳轉登錄界面
- (void)goNativeLogin;
//跳轉掃碼界面
- (void)scanBarcode;
//獲取本地用戶信息
- (void)getNativeUserInfo;
//H5界面跳轉到本地控制器,通過url進行跳轉
- (void)gotoNativeView:(id)url;
@end
然后在TPNativeFunctionTool.m文件中實現(xiàn)這些方法
- (void)goBackNative{
[self.vc.navigationController popViewControllerAnimated:YES];
}
- (void)goNativePay:(id)json{
ThirdPayViewController *payVc = [[ThirdPayViewController alloc] init];
payVc.orderNum = @"XXXXXXXXXXXXX";
payVc.OrderType = @"0";
[self.vc.navigationController pushViewController:payVc animated:YES];
}
- (void)goNativeLogin{
LoginViewController *loginVc = [[LoginViewController alloc] init];
[self.vc.navigationController pushViewController:loginVc animated:YES];
}
- (void)scanBarcode{
TPH5ScanQRCodeViewController *qrVc = [[TPH5ScanQRCodeViewController alloc] init];
qrVc.style = [self getScanStyle];
tpWeakSelf
//回調掃描結果
qrVc.result = ^(NSString *result){
weakSelf.QRCodeResult = result;
};
[self.vc.navigationController pushViewController:qrVc animated:YES];
}
- (void)getNativeUserInfo{
}
native控制器端的代碼:
(1)生成一個js環(huán)境:
/*
*懶加載一個js環(huán)境
*/
- (JSContext *)context{
if (!_context) {
_context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
}
return _context;
}
(2)webView的webViewDidFinishLoad代理方法中,關聯(lián)我們的native對象,注意點是必須關聯(lián)到才能進行交互
/*需要關聯(lián)的類*/
- (TPNativeFunctionTool *)native{
if (!_native) {
_native = [[TPNativeFunctionTool alloc] initWithVc:self];
}
return _native;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//這個對象就是我們遵守了JSExport協(xié)議的那個類
self.context[@"nativeObj"] = self.native;
這樣,我們就已經實現(xiàn)了最基本的跳轉交互了,是不是很神奇,我也覺得.但我們如何將參數(shù)回調給H5呢?這時我們需要實現(xiàn)如下方法(只舉一個例子,后面都大同小異):
//回調二維碼掃描參數(shù)
- (void)getQRCode{
//通過context獲得js中scanBarcodeCallback方法的環(huán)境
//JSValue可以用來獲取js中的方法
JSValue *func = self.context[@"scanBarcodeCallback"];
//回調的二維碼參數(shù)
NSString *result = self.native.QRCodeResult;
if (result == nil) return;
//回調的參數(shù)格式
NSString *code = @"1";
NSDictionary *data = @{@"data":result};
NSString *msg = @"";
NSDictionary *resultDict = @{@"code":code,@"data":data,@"msg":msg};
//將字典轉化成json串,進行回調
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:resultDict options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonResult = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
//通過callWithArguments方法來進行參數(shù)回調即可
[func callWithArguments:@[jsonResult]];
}
2.通過url跳轉到本地控制器
這里我用的是DCURLRoutter,來進行url的跳轉,詳情請點擊查看.
項目中的代碼:
/*注釋:傳入一個url,url包含了一個協(xié)議頭和對應控制器的映射參數(shù),
經過DCLURLRouter的解析后,轉換成對應的控制器,然后進行跳轉.例如url是"native://login"==>"LoginViewController"這個控制器,我們只需要傳入"native://login"就能進行對應的跳轉*/
//這里我封裝了它的方法
+ (void)PushNativeViewController:(NSString *)url animated:(BOOL)Yes{
[DCURLRouter pushURLString:url animated:YES];
}
3.在native中編寫js代碼,這里我的實用場景是,服務器返回的HTML中圖片尺寸過大, 于是在native中添加js代碼進行規(guī)范
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSString *js = @"function imgAutoFit() { \
var imgs = document.getElementsByTagName('img'); \
for (var i = 0; i < imgs.length; ++i) {\
var img = imgs[i]; \
img.style.maxWidth = %f; \
} \
}";
js = [NSString stringWithFormat:js, [UIScreen mainScreen].bounds.size.width - 20];
[webView stringByEvaluatingJavaScriptFromString:js];
[webView stringByEvaluatingJavaScriptFromString:@"imgAutoFit()"];
}
其實還嘗試過WKWebView的交互方式,可項目中不利于和安卓的統(tǒng)一,就放棄了,那種方式也是一種非常簡單明了的交互方式,有興趣的同學可以自行去研究下.