iOS 開發與H5交互(JavaScriptCore框架的使用)


現在的iOS項目中嵌入了越來越多的Web界面,當然是為了方便,那么為了迎合這一趨勢,作為iOS開發程序員,我們必須要了解怎么樣用OC去和這些Web界面進行交互。這里介紹的是JavaScriptCore這個框架,他就是蘋果為了解決這一問題而推出的框架。

JavaScriptCore的類說明

在做OC與H5的交互之前,我們需要先導入JavaScriptCore框架

#import <JavaScriptCore/JavaScriptCore.h>

然后我們進入到JavaScriptCore框架的JavaScriptCore.h,我們發現總共有如下幾個類。

#if defined(__OBJC__) && JSC_OBJC_API_ENABLED

#import "JSContext.h"
#import "JSValue.h"
#import "JSManagedValue.h"
#import "JSVirtualMachine.h"
#import "JSExport.h"

#endif

1. JSContext

JSContext 代表一個JavaScript的執行環境的一個實例。所有的JavaScript執行都是在上下文內。作為上下文,我們在很多情況下遇到過,比如CoreData,CoreGraphics等等,那么上下文對象到底是什么呢?你可以理解為是一個兩者的連接橋梁,如圖所示.

2.JSValue

JSValue的主要作用就是用來接收JSContext執行后的返回結果,當然了,JSValue可以是Js的任意類型。例如,JS中的變量,對象,以及函數。下面,我們舉個例子來說明一下,例如我們現在需要從JSContext對象中接收到一個變量,我們可以如下所示。

首先在<script>標簽中我們定義了一個字符串變量

  <script type="text/javascript">
        var myObject = "myObject";
    </script>

然后,我們在OC的代碼中如下表示,其中self.context代表着已經初始化完成的JSContext對象。

JSContext 對象的創建有兩種方法

/*使用這個方法進行初始化 系統會自動創建一個JSVirtualMachine對象 然后 調用下面的方法 */
- (instancetype)init; /*! JSVirtualMachine對象其實代表着一個JavaScript對象空間或者一組執行資源。初始化只需要init 就行了 */ - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;

當然 如果你使用了WebView 你可以這樣初始化一個JSContext對象

JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

有了JSContext,我們只需要在OC中寫出下面的代碼,就可以拿到我們在JS中定義的變量了

JSValue *value = self.context[@"myObject"]; //轉換為OC的字符串 NSLog(@"%@",[value toString]);

3.JSManagedValue

JSManagedValue這個類其實到現在我還沒有具體用到過.當時這里我也要根據API文檔說明一下.JSManagedValue是JSValue的封裝,用它可以解決JS和OC代碼之間循環引用的問題,JSManagedValue最常用的用法就是安全的從內存堆區里面引用JSValue對象.如果JSValue存儲在內存的堆區的方式是不正確的,很容易造成循環引用,然后導致JSContext對象不能正確的釋放掉.

4.JSValueMachine

一個JSVirtualMachine對象其實代表着一個JavaScript對象空間或者一組執行資源。JSVirtualMachine支持線程安全鎖,虛擬機,並發分配支持的JavaScript執行.也就說JSVirtualMachine用來管理整個JavaScript,當然了,這個類我也沒有用到過.

5.JSExport

JSExport是一個協議,通過實現它可以完成把一個native對象暴漏給JS,當然了我們要指定native對象.比如我們指定native對象就是自身.如下所示.

self.context[@"native"] = self;

JavaScript 調取 OC的代碼

那么我們怎么使用JavaScriptCore 進行JS與OC的交互呢,我們先來介紹JS調取OC的代碼的方法。主要有兩種方法:一種是很簡單的直接使用Block,另一種是使用JSExport協議。

Block方式

block的方式比較簡單,也是我比較推薦的一種,但是要注意防止循環引用問題。首先 我們說一下不帶參數的函數調用,也就是我們不需要從網頁那邊有參數的傳值。比如,頁面跳轉等等,代碼如下:

HTML文件中的<body>標簽中的按鈕代碼

<button type="button" onclick="buttonClick()">點擊按鈕返回上一個頁面</button>

OC中在- (void)webViewDidFinishLoad:(UIWebView *)webView方法中對block塊進行代碼實現.

__weak typeof(self)weakSelf = self;
    self.context[@"buttonClick"] = ^() {
        [weakSelf.navigationController popViewControllerAnimated:YES];
    };

這樣當你點擊Web頁面上的按鈕的時候,就會執行block中的代碼。進行頁面跳轉。

接下來 我們看一下,通過頁面的傳值,我們把H5標簽的之作為參數進行傳值操作。並且調用OC的block進行打印。

HTML文件中的<body>標簽中的代碼

<body bgcolor="antiquewhite">

        <!--&lt;!&ndash;打開本地 或者網頁&ndash;&gt;-->
        <!--<a href="news.html" target="_top">打開本地</a>-->
        <!--<h1 align="center">標題一</h1>-->
        <!--<h2 class="h2ID">標題2</h2>-->
        <button type="button" onclick="buttonClick('你好','世界')">點擊按鈕返回上一個頁面</button>
        <script type="text/javascript">
            function buttonClick(str1,str2) {
                alert(str1 + "---" + str2);
            }
        </script>
    </body>

OC調用這個block中的代碼 有兩種方法

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //第一種方法
//    self.context[@"buttonClick"] = ^() {
//        //獲取該方法的所有參數
//        NSArray *args = [JSContext currentArguments];
//        for (JSValue *arg in args) {
//            NSLog(@"%@",arg);
//        }
//        
//    };
    //第二種方法
    self.context[@"buttonClick"] = ^(NSString *str1,NSString *str2) {
        NSLog(@"%@ and %@",str1,str2);
    };
}

點擊按鈕 可以看到 打印結果 你好 世界

JSExport 協議方式

通過實現JSExport協議方式進行OC與JS的交互,這里我只是簡單的實現以下沒有參數的函數調用.首先,我們在HTML文件中創建一個按鈕用來調用OC中JSExport協議方法.

聲明一個person類

.h
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>


@protocol webJsExport <JSExport>

- (void) myButtonClick;


@end

@interface Person : NSObject<webJsExport>



@end
.m

#import "Person.h"

@implementation Person

- (void)myButtonClick {
    NSLog(@"再來一次");
}

@end

HTML

<button type="button" onclick="stu.myButtonClick()">JSExport沒有參數</button>

調用

- (void)viewDidLoad {
    [super viewDidLoad];
    self.p = [[Person alloc] init];
    self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
    self.webView.delegate = self;
    NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Index" ofType:@"html"];
    NSString *html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [self.webView loadHTMLString:html baseURL:baseURL];
    [self.view addSubview:self.webView];
//    self.context = [[JSContext alloc] init];
//    JSValue *value = self.context[@"myObject"];
//    //轉換為OC的字符串
//    NSLog(@"%@",[value toString]);
//    __weak typeof(self)weakSelf = self;
//    self.context[@"buttonClick"] = ^() {
//        [weakSelf.navigationController popViewControllerAnimated:YES];
//    };
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    //第一種方法
//    self.context[@"buttonClick"] = ^() {
//        //獲取該方法的所有參數
//        NSArray *args = [JSContext currentArguments];
//        for (JSValue *arg in args) {
//            NSLog(@"%@",arg);
//        }
//        
//    };
    //第二種方法
    self.context[@"buttonClick"] = ^(NSString *str1,NSString *str2) {
        NSLog(@"%@ and %@",str1,str2);
    };
    self.context[@"stu"] = self.p;
    
    
}

點擊JSExport沒有參數 會打印:在來一次

OC調用JavaScript函數

今天我們說一下如何使用JavaScriptCore讓OC調用JavaScript函數,使用JavaScriptCore進行OC調用JavaScript函數是很容易進行傳值操作的.首先我們需要在HTML文件創建愛你一個帶有id的標簽以及一個JavaScript函數.代碼如下所示.

HTML代碼

 <b id="label">需要改變的標簽</b>
    <script type="text/javascript">
        function labelAction(obj) {

            document.getElementById('label').innerHTML = obj;

        }
    </script>

然后 就是OC中的代碼了

下面就是實現方法,首先我們要先通過JSContext對象獲取到JS中的對應函數並且使用JSValue對象進行接收.然后我們通過使用- (JSValue *)callWithArguments:(NSArray *)arguments;進行JS函數的調用,當然了這里的JS函數沒有返回值,我也就沒有做接收返回值的工作.

-(void)changeWebTxet{
    JSValue *labelAction = self.context[@"labelAction"];
    [labelAction callWithArguments:@[@"你好,JS世界!"]];
}

通過上面的介紹,我們可以看出來 使用JavaScriptCore 來進行OC與H5 的交互是很方便的,比以前通過WebView的一些方法交互方便多了。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM