ios与html交互(UIWebView)

基于UIWebView ios与js交互

githubdemo:
https://github.com/wangjinshan/JSWebDemo
https://github.com/wangjinshan/JSCDemo

ios 原声界面上加载webview, 然后需要和web界面进行数据交互就需要用到 ios和js 交互的知识, 交互的方法有三种:
1, 今天要讲解的基于 UIWebView的 交互,这种方式最主要的思想就是通过网页的代码方法进行url的拦截操作,后面细讲
2 第三方库
3, 苹果为我们封装 JavaScriptCore.framework

实例讲解

1,配置基本环境
创建 Sample.html ShareSDK.css ShareSDK.js 实现界面布局并加载到本地

  代理  UIWebViewDelegate
  NSString *path = [[NSBundle mainBundle]pathForResource:@"Sample" ofType:@"html"];
    NSURL*htmlURL = [NSURL fileURLWithPath:path];
    self.webView =[[UIWebView alloc]initWithFrame:self.view.bounds];
    NSURLRequest *request =[NSURLRequest requestWithURL:htmlURL];
    [_webView loadRequest:request];
    _webView.delegate = self;
    [self.view addSubview:_webView];

以下以在html上集成集成 ShareSDK 为例子, 由于前期数据传输没整理好,大家先忽略数据传递的问题,文章后面会补充
1, ShareSDK 初始化 ,创建一个 名字叫ShareSDK的对象 并在里面实现 initSDK初始化方法 ,数据暂时将以数组的形式传递,后面再补充上对象json传递

function ShareSDK()
{
//    初始化sdk, 注意 此处必须写上this 否则外部调用失败
    this.initSDK = function()
    {
        //1,平台的参数
        var mobkey = 'iosv1101';
        var platformID = new PlatformID();
        //平台数组
        var platformArr = [platformID.platformID.WeChat,platformID.platformID.WeChatFavorites,platformID.platformID.WeChatMoments];
        //2,微信appkey
        var platformConfig = ["wx4868b35061f87885","64020361b8ec4c99936c0e3999a9f249"];
        //发送请求
        window.location.href = '&initSDK' + '&mobkey'+mobkey +'&platformArr'+ platformArr +'&platformConfig' + platformConfig;
    }
}
var $sharesdk = new ShareSDK();

大家先简单理解这个就是一个 js方法,下面我们要做的就是在 ios上调用这段代码
我们已经在 viewDidLoad 的方法中加载了网页 下面我们就签UIWebView协议 UIWebViewDelegate 并实现代理方法

ios 调用 js代码

ios 调用js 代码非常简单,UIWebView 已经为我们封装好了方法(stringByEvaluatingJavaScriptFromString),我们将在网页加载完毕后进行代码处理,注意必须在网页加载完毕才能操作,否则无效

// 网页完成加载
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
//  注意stringByEvaluatingJavaScriptFromString必须保证是在主线线程中完成任务
    [self.webView stringByEvaluatingJavaScriptFromString:@"window.$sharesdk.initSDK()"];
    NSLog(@"----1------%@",[NSThread currentThread]);   //线程是1
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_sync(queue, ^{
        NSLog(@"----2-----%@",[NSThread currentThread]); //线程还是1
         [self.webView stringByEvaluatingJavaScriptFromString:@"window.$sharesdk.ajsTest()"];
    });
}

注意 (stringByEvaluatingJavaScriptFromString) 这个方法必须在主线程调用,否则崩溃,如下

Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...

代码注释: ios 调用js 相当于 给 js 发送一段字符串,然后程序会根据字符串去环境中寻找对应的方法并执行, @"window.$sharesdk.initSDK()" window js是环境中的全局变量, 所有 js环境中方法和属性 ,都可以通过 window 来进行调用, 此处 window 去找到 sharesdk对象并执行 initSDK()的方法
检查 方法有没有被调用 可以在 initSDK(); 进行 alert();进行测试,弹出警告窗口则表示调用成功

js 调用 ios代码

js调用 ios 也非常的简单,就是js发送一段请求,然后ios 在代理方法中进行拦截,如下

 this.initSDK = function()
    {
        //发送请求
        window.location.href = '要发送的数据';
    }

js 中 只要遇到 window.location.href 就会通知 ios 执行回调方法, html 进行 某个时段进行固定跳转也是经过这个方法, 下面我们就可以到 ios 对这段数据进行解析

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    [self analyzeURL:request.URL];
    return YES;   // 必须返回 yes
}

以上方法中的 request 就携带了 window.location.href = '要发送的数据'; 这个方法中 携带的 [要发送的数据], 这是一段 json 数据 ,解析这段json数据 你就可以进行相关的操作了, 到此 ios调用 js is调用ios结束,感觉非常简单, 但是你发现没有, 以上的实现并没有牵扯到数据, 个人认为 交互最蛋疼一点就是数据传递, UIWebView 并不友好, 数据传递比较蛋疼

js 传递数据给 ios

上面说过 js 调用 ios 是通过 发送请求的方法 (window.location.href = '要发送的数据';) 但是这个数据到底应该怎么写? 如下

//    测试传递对象类型
    this.ajsTest = function ()
    {
        var backJson = {};
        var wjs =
        {
            "name":"神族科技CEO",
            "name":"金山",
            "city":"上海"
        };
        backJson["wjs"] = wjs;
        var wjsJson =  ObjectToJsonString(backJson);
        window.location.href ="ajstest://?"+wjsJson;    // 注意协议头必须是小写 大写将转换成小写
    }

通常为了解析方便,我们都会携带一个协议,这个协议头可以随便写,然后拼接你要的数据,上面的例子 传递的是 一个js 中的对象,我们需要将 对象转换成 js 格式的字符串, 方法就是

var JsonStringToObject = function (string)
{
    try
    {
        return eval("(" + string + ")");
    }
    catch (err)
    {
        return null;
    }
};

这样就可以把js中的对象数据传给ios使用,ios拦截到的依然是个 json的字符串需要你手动解析
由于 URL是有长度的限制的,并且location.href管理页面的url,用location.href=url 是直接将页面重定向url,所以我们采用 hash属性,不让界面定位到某一个url而是定位到界面的某一个锚点, 所以实际的开发建议使用:
window.location.hash ="http://test#" + 传递的json数据;
数据解析正常

ios传递数据给js

ios 传递数据给 js 实现和ios 调用js 代码一样,只需要将传递的数据拼接在后面就可以

[errorDic setObject:[NSDictionary dictionaryWithObjectsAndKeys:
                                         [NSNumber numberWithInteger:[error code]],
                                         @"error_code",
                                         [error userInfo],
                                         @"error_msg",
                                         nil]
                                 forKey:@"error"];
                    [self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"$sharesdk.callBackData('%@')",[self jsonStringFromObject:errorDic]]];
/**
 *  对象序列化为Json字符串
 *
 *  @param object 任意对象
 *
 *  @return Json字符串
 */
- (NSString *)jsonStringFromObject:(id)object
{
    NSString *jsonString = [[NSString alloc]init];
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object
                                                      options:NSJSONWritingPrettyPrinted
                                                        error:&error];
    if (! jsonData) {
        NSLog(@"error: %@", error);
    } else {
        jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0,jsonString.length};
    [mutStr replaceOccurrencesOfString:@" "withString:@""options:NSLiteralSearch range:range];
    NSRange range2 = {0,mutStr.length};
    [mutStr replaceOccurrencesOfString:@"\n"withString:@""options:NSLiteralSearch range:range2];
    return mutStr;
}

这样就是实现了 ios 把一个 ios对象 转换成json 对象并 传给 js 使用
到此 基于 UIWebView 的 ios与js交互全部结束
完美的分割线
参考 window.location.hash 解释
http://www.bbsmax.com/R/q4zVMWQldK/

UIWebView 交互存在一个问题 一个html 不能同时发送 两个 window.location.hash = "";

解决这个问题的方案 就是需要结合 利用location.hash+iframe跨域获取数据详解
http://www.bbsmax.com/A/A2dmxyan5e/
这个问题后面 会抽时间更新

谢谢大家


你可能感兴趣的:(ios与html交互(UIWebView))