欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS与网页JS交互

程序员文章站 2022-05-25 15:42:13
随着移动app的快速迭代开发趋势,越来越多的app中嵌入了html网页,但在一些大中型app中,尤其是电商类app,html页面已经不仅仅满足展示功能,这时html要求能与原生语言进行交互、相互传...

随着移动app的快速迭代开发趋势,越来越多的app中嵌入了html网页,但在一些大中型app中,尤其是电商类app,html页面已经不仅仅满足展示功能,这时html要求能与原生语言进行交互、相互传值。比如携程app中一个热门景点的网页中,点击某个景点,可以跳转到原生中的该景点详情页控制器。

为此,我整理了三种最常用最便捷有效的oc与js交互的方式,供大家学习交流。

第一种:js给oc传值。

1. 技术方案:使用javascriptcore.framework框架
2. 使用场景: 网页中代码中的某个方法,比如点击事件方法,将该方法的参数传值给oc,供oc使用。
比如:携程app中一个热门景点的网页中,有很多个热门景点,点击某个景点的图片或名称,可以跳转到原生中的该景点详情页控制器。
3. 代码实现如下:

oc里要实现的代码:

拖入javascriptcore.framework静态库,遵守uiwebviewdelegate代理协议。
在-webviewdidfinishload:方法里编写如下代码:

- (void)webviewdidfinishload:(uiwebview *)webview{

    jscontext *context = [webview valueforkeypath:@"documentview.webview.mainframe.javascriptcontext"];

    context[@"passvalue"] = ^{

        nsarray *arg = [jscontext currentarguments];
        for (id obj in arg) {
            nslog(@"%@", obj);
        }
    };

}

其中 passvalue 是js的函数名,得到的 arg数组 里面为js的 passvalue 函数的参数,即 js要传给oc的参数

js里要实现的代码:

function testclick()
            {
                var str1=document.getelementbyid("text1").value;
                var str2=document.getelementbyid("text2").value;

                passvalue(str1,str2);
            }

在需要给oc传值的函数里(例如:testclick())直接调用 passvalue()函数,将值传进去即可。


第二种:js给oc传值。

1. 技术方案:使用自定义url方法,每次点击网页
2. 使用场景: 网页中代码中的某个方法,比如点击事件方法,将该方法的参数传值给oc,供oc使用。
比如:携程app中一个热门景点的网页中,有很多个热门景点,点击某个景点的图片或名称,可以跳转到原生中的该景点详情页控制器。
3. 代码实现如下:

js里要实现的代码:

  function testclick()
            {

                var str1=document.getelementbyid("text1").value;
                var str2=document.getelementbyid("text2").value;

                //  "objc://"为自定义协议头;
                //  str1&str2为要传给oc的值,以":/"作为分隔
                window.location.href="objc://"+":/"+str1+":/"+str2;
            }

在需要给oc传值的函数里(例如:testclick())写如上格式的代码。

其中 objc:// 是自定义的协议头,str1与str2为js要传给oc的值

oc里要实现的代码:

//遵守uiwebviewdelegate代理协议。
-(bool)webview:(uiwebview *)webview shouldstartloadwithrequest:(nsurlrequest *)request navigationtype:(uiwebviewnavigationtype)navigationtype{
    //拿到网页的实时url
    nsstring *requeststr = [[request.url absolutestring] stringbyremovingpercentencoding];

    //在url中寻找自定义协议头"objc://"
    if ([requeststr hasprefix:@"objc://"]) {

        // 以"://"为中心将url分割成两部分,放进数组arr
        nsarray *arr = [requeststr componentsseparatedbystring:@"://"];
        nslog(@"%@",arr);

        //取其后半段
        nsstring *paramstr = arr[1];
        nslog(@"%@",paramstr);

        //以":/"为标识将后半段url分割成若*分,放进数组arr2,此时arr2[0]为空,arr2[1]为第一个传参值,arr2[2]为第二个传参值,以此类推
        nsarray *arr2 = [paramstr componentsseparatedbystring:@":/"];
        nslog(@"%@",arr2);

        //取出参数,进行使用
        if (arr2.count) {
            nslog(@"有参数");
            [self dosomethingwithparama:arr2[1] andparamb:arr2[2]];
        }else{
            nslog(@"无参数");
        }
        return no;
    }

    return yes;
}
//对js传来的值进行调用
- (void)dosomethingwithparama:(id)parama andparamb:(id)paramb{

    nslog(@"%@    %@", parama, paramb);
}

第三种:利用第三方库实现js与oc的相互传值。

1. 技术方案:使用webviewjavascriptbridge三方库
2. 使用场景: 网页中代码中的某个方法,比如点击事件方法,将该方法的参数传值给oc,供oc使用。
比如:携程app中一个热门景点的网页中,有很多个热门景点,点击某个景点的图片或名称,可以跳转到原生中的该景点详情页控制器。
或者将原生中的用户信息传递给网页,以便其个性化展示
3. 代码实现如下:

oc传值给js

js里需要实现的代码:

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 = 'wvjbscheme://__bridge_loaded__';
        document.documentelement.appendchild(wvjbiframe);
        settimeout(function() { document.documentelement.removechild(wvjbiframe) }, 0)
    }

    //调用上面定义的函数
    setupwebviewjavascriptbridge(function (bridge){

        //oc传值给js 'testjavascripthandler'为双方自定义好的统一方法名;'data'是oc传过来的值;'responsecallback'是js接收到之后给oc的回调
        bridge.registerhandler('testjavascripthandler', function(data, responsecallback) {
                //打印oc传过来的值
                log('objc called testjavascripthandler with', data)

                var responsedata = { 'javascript says':'right back atcha!' }

                log('js responding with', responsedata)

                //给oc的回调
                responsecallback(responsedata)

            })

oc里需要实现的代码:

导入第三方库webviewjavascriptbridge;遵守uiwebviewdelegate;

    //设置第三方bridge是否可用
    [webviewjavascriptbridge enablelogging];

    //关联webview和bridge
    _bridge = [webviewjavascriptbridge bridgeforwebview:web];

    [_bridge setwebviewdelegate:self];

    //oc给js传值,双方自定义一个统一的方法名'testjavascripthandler';data里即为要传过去的值
    [_bridge callhandler:@"testjavascripthandler" data:@{@"年龄":@"20"}];

js传值给oc

js里需要实现的代码:

     //点击网页上一个按钮时
     callbackbt.onclick = function()
     {  
     var str1=document.getelementbyid("text1").value;
     var str2=document.getelementbyid("text2").value;

     //js给oc传值。'passvalue'为双方自定义的统一方法名;'str1'&'str2'为要传的值; response为oc收到后给js的回调
     bridge.callhandler('passvalue', {str1,str2}, function(response) {
                                })

     }

oc里需要实现的代码:

导入第三方库webviewjavascriptbridge;遵守uiwebviewdelegate;

   //设置第三方bridge是否可用
    [webviewjavascriptbridge enablelogging];

    //关联webview和bridge
    _bridge = [webviewjavascriptbridge bridgeforwebview:web];

    [_bridge setwebviewdelegate:self];

    //js给oc传值.'passvalue'为双方自定义的统一方法名;'data'为js传过来的值;'responsecallback'为oc收到值后给js返回的回调
    [_bridge registerhandler:@"passvalue" handler:^(id data, wvjbresponsecallback responsecallback) {

        //打印js传过来的值
        nslog(@"%@", data);

        //返回给js的值
        responsecallback(@"收到了");
    }];

需要注意的是:不论哪方给哪方传值,传值的方法名称与对应接收值的方法名称要保持一致。

有任何问题,大家可以在评论区留言,我会一一解答。