10分鐘 搞定JS和OC交互

JS和iOS的交互

JS和iOS交互,是每個應用都少不了的需求,尤其是在頁面變動比較大的情況,頁面經常更新,JS和iOS交互用起來就很幸福了。

原理:
通過JavaScriptCore解決JS和iOS之間的交互

說明:
JavaScriptCore是封裝了JavaScript和Objective-C橋接的Objective-C API,只需要較少的的代碼,就可以實現JavaScript與Objective-C的相互調用。
  iOS7之后蘋果推出了JavaScriptCore這個框架,從而讓web頁面和本地原生應用交互起來非常方便,而且使用此框架可以做到Android那邊和iOS相對統(tǒng)一,web前端寫一套代碼就可以適配客戶端的兩個平臺,從而減少了web前端的工作量。
iOS和Android協商好定義方法名稱,然后把這個名稱告知h5即可,在這里其實也可以有h5定義好,告知我們,這樣減少我們的協商。
JavaScriptCore中web頁面調用原生應用的方法可以用Delegate或Block兩種方法,這里用block實現方法,因為block的方法更加簡單一點。

JavaScriptCore中類及協議:
JSContext:給JavaScript提供運行的上下文環(huán)境,JSContext是代表JS的執(zhí)行環(huán)境,通過-evaluateScript:方法就可以執(zhí)行一JS代碼
JSValue:JSValue封裝了JS與ObjC中的對應的類型,以及調用JS的API等,可以理解為JavaScript和Objective-C數據和方法的橋梁
JSManagedValue:管理數據和方法的類
JSVirtualMachine:處理線程相關,使用較少
JSExport:JSExport是一個協議,遵守此協議,就可以定義我們自己的協議,在協議中聲明的API都會在JS中暴露出來,才能調用

進入正題

一、貼上h5的代碼

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
            <script type="text/javascript">
                
                var share = JSON.stringify({"title": "Migi000",
                                           "desc": "簡書",
                                           "shareUrl": "http://www.itdecent.cn/p/f896d73c670a"
                                           });
            
            //IOS
            function startFunction(share){
                window.android.startFunction(share)//android
            }
            
                </script>
    </head>
    <body>
        <br/>
        <h1>Objective-C和JavaScript交互的那些事</h1> <br/>
        <input  type="button" value="Share" onClick="startFunction(share)" >點擊調用原生代碼并傳遞參數</a>

            </body>
</html>

注釋:這里的方法要寫在head里面,PS:在測試這段代碼之前,本身方法是寫在body中,但是Android不能實現,后來放在head中就可以實現,這個沒有太多了解是什么原因,有大神可以指教

二、快速接入 - block解決
.m文件如下

//
//  ViewController.m
//  jsTest
//
//  Created by fangpinhui on 16/5/18.
//  Copyright ? 2016年 Lumic. All rights reserved.
//

#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>

@interface ViewController ()<UIWebViewDelegate>
@property (nonatomic)UIWebView *webView;
@property (nonatomic)JSContext *jsContext;
@property (nonnull,strong) UIButton *btn;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.webView = [[UIWebView alloc]initWithFrame:self.view.bounds];
    self.webView.delegate = self;
    [self.view addSubview:_webView];
    NSString *str = [[NSBundle mainBundle] pathForResource:@"migi" ofType:@"html"];
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:@"f"]]];
//    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.1.59:8020/Online-Booking/index.html"]]];
    
    //  在上面添加一個按鈕,實現oc端控制h5實現彈alert方法框
    self.btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 400, 100, 40)];
    self.btn.backgroundColor = [UIColor redColor];
    [self.btn addTarget:self action:@selector(showAlert) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.btn];
    
    
}
- (void)showAlert
{
    //要將script的alert()方法轉化為string類型
    NSString *alertJs=@"alert('Hello Word')";
    [_jsContext evaluateScript:alertJs];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView{
    _jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    _jsContext[@"startFunction"] =^(id obj){
////這里通過block回調從而獲得h5傳來的json數據
        /*block中捕獲JSContexts
        我們知道block會默認強引用它所捕獲的對象,如下代碼所示,如果block中直接使用context也會造成循環(huán)引用,這使用我們最好采用[JSContext currentContext]來獲取當前的JSContext:
         */
        [JSContext currentContext];
        NSData *data = [(NSString *)obj dataUsingEncoding:NSUTF8StringEncoding ];
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
        NSLog(@" data   %@   ======  ShareUrl %@",obj,dict[@"shareUrl"]);
    };
    //
    _jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        //比如把js中的方法名改掉,OC找不到相應方法,這里就會打印異常信息
        NSLog(@"異常信息:%@", exceptionValue);
    };
  

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

注釋:
1.#import <JavaScriptCore/JavaScriptCore.h> 導入放在.h文件中
2.因為這里h5需要調用我們的Native定義的startFunction 方法,以及需要的回調的數據格式,所以這里需要和h5溝通一下

這就是簡單的js和oc之間的交互,可以使用在平臺的應用中,下面是遇到的問題匯總,如有遇到問題,積極分享咯!

問題匯總:
問題1.
在執(zhí)行回調時,iOS可以實現回調方法,而Android無法實現,雙發(fā)都檢查了代碼,沒有問題,檢查h5代碼時,發(fā)現方法寫在body中,Android無法實現回調

解決辦法:
h5的方法寫在head中,實現了,好吧,大神指導好嗎?

問題2:
在進行js和iOS的交互時,我寫了個代碼,demo中我把#import <JavaScriptCore/JavaScriptCore.h>
庫的引入放在了.m文件中,block回調時拿到了數據,但是當在公司項目中實現時,怎么都不執(zhí)行回調方法,很是詭異,怎么都無法實現,

解決辦法:
把庫的導入#import <JavaScriptCore/JavaScriptCore.h> 放在.h文件中就執(zhí)行了。滿面懵逼!,求指教

PS:來簡書混,關注是必須的,點贊?? 是要給的!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容