DSBridge 原生和H5交互

DSBridge 原生和H5交互看这里

之前用的WebViewJavascriptBridge和前端交互, 现在公司前端说统一用DSBridge, 研究了一下写了个demo, 分享给小伙纸们😃

三端易用的现代跨平台 Javascript bridge, 通过它,你可以在Javascript和原生之间同步或异步的调用彼此的函数.
https://github.com/wendux/DSBridge-IOS

特性

  1. Android、IOS、Javascript 三端易用,轻量且强大、安全且健壮。
  2. 同时支持同步调用和异步调用
  3. 支持以类的方式集中统一管理API
  4. 支持API命名空间
  5. 支持调试模式
  6. 支持API存在性检测
  7. 支持进度回调:一次调用,多次返回
  8. 支持Javascript关闭页面事件回调
  9. 支持Javascript 模态/非模态对话框
  10. Android端支持腾讯X5内核

安装

pod "dsBridge"

使用

  1. 新建一个类,实现API JS调用原生方法

//JS调用原生方法类

import Foundation
typealias JSCallback = (String, Bool)->Void

class JsApiTestSwift: NSObject {
 
 
 var value = 10
 var feedbankHandler : JSCallback?
 var valueTimer: Timer?
 
 // MARK: - 测试同步方法
 //MUST use "_" to ignore the first argument name explicitly。
 @objc func testSyn( _ arg:String) -> String {
     print("js调用了原生的testSyn方法")
     return String(format:"%@[Swift sync call:%@]", arg, "test")
 }
 // MARK: - 测试异步有回调
 @objc func testAsyn( _ arg:String, handler: JSCallback) {
     print("js调用了原生的testAsyn方法")
     handler(String(format:"%@[Swift async call:%@]", arg, "test"), true)
 }
 
 // MARK: - 带有dic参数的
 @objc func testNoArgSyn( _ args:Dictionary<String, Any>) -> String{
     print("js调用了原生的testNoArgSyn方法")
     return String("带有dic参数的的方法")
 }
 
 // MARK: - 持续返回进度
 @objc func callProgress( _ args:Dictionary<String, Any> , handler: @escaping JSCallback ){
     print("js调用了原生的callProgress方法")
     feedbankHandler = handler
     valueTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(feedbackValue), userInfo: nil, repeats: true)
     
 }
 //返回进度value
 @objc func feedbackValue() {
     
     if let handler = feedbankHandler {
         if value > 0{
             handler(String(value), false)//上传中
             value -= 1
         }else {
             handler(String(value), true)//上传完成
         }
     }
 }
 

}


可以看到,DSBridge正式通过API类的方式集中、统一地管理API。

  1. 新建一个UIViewController, 用来展示页面
import UIKit

class DSbridgeViewController: UIViewController {

    private var webview:JMWebView = {
        let webview:JMWebView = JMWebView.init()
        return webview
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //设置webview
        setupWebview()
        
        //JS调用原生
        addJsMethod()
        
        //原生调用JS
        nativeCallJS()
    }
    
    // MARK: - 设置Webview
    private func setupWebview() {
        webview.frame = self.view.bounds
        self.view.addSubview(webview)
        
        #if DEBUG
        webview.setDebugMode(true)
        #endif
        
        webview.customJavascriptDialogLabelTitles(["alertTitle" : "Notification",  "alertBtn" : "OK"])
        webview.navigationDelegate = self
        
        let baseUrl = URL.init(fileURLWithPath: Bundle.main.bundlePath)
        let htmlPath = Bundle.main.path(forResource: "test", ofType: "html") ?? ""
        let htmlContent = (try? String.init(contentsOfFile: htmlPath, encoding: String.Encoding.utf8)) ?? ""
        
        webview.loadHTMLString(htmlContent, baseURL: baseUrl)
    }
    
    // MARK: - JS调用原生
    private func addJsMethod() {
        //添加原生方法类
        webview.addJavascriptObject(JsApiTestSwift.init(), namespace: nil)
        webview.addJavascriptObject(JsApiTestSwift.init(), namespace: "swift")//增加命名空间, JS在调用的时候可以用 swift.methodName 方便管理功能模块可增强阅读
    }

    
    // MARK: - 原生调用JS
    private func nativeCallJS() {
        
        //原生调用js的addValue方法, 参数是[3, 4], 返回值是value
        webview.callHandler("addValue", arguments: [3, 4]) { (value) in
            print(value ?? "")
        }
        //拼接字符串
        webview.callHandler("append", arguments: ["I", "love", "you"]) { (value) in
            print(value ?? "")
        }
        //传递json
        let dic: Dictionary = ["name": "weixiang", "sex": "male"]
        let jsonStr: String = dicToString(dic) ?? ""
        webview.callHandler("showJson", arguments: [jsonStr]) { (value) in
            print(value ?? "")
        }
        
        //收到result 为json
        let dic1: Dictionary = ["name": "zhangsan", "sex": "male"]
        let jsonStr1: String = dicToString(dic1) ?? ""
        webview.callHandler("showResult", arguments: [jsonStr1]) { (value) in
            print(value ?? "")  
        }

        webview.callHandler("startTimer") { (value) in
            print(value ?? "")
        }
        
        //带有命名空间的方法
        webview.callHandler("syn.addValue", arguments: [5, 6]) { (value) in
            
            print(value as Any)
        }

        //测试是否js有这个方法
        webview.hasJavascriptMethod("addValue") { (isHas) in
            print(isHas)
        }
        
        //如果H5调用了window.close方法就会监听到
        webview.setJavascriptCloseWindowListener {
            print("监听到关闭H5页面")
        }
        

    }

}

添加API类实例到 DWKWebView

   // MARK: - JS调用原生
 private func addJsMethod() {
     //添加原生方法类
     webview.addJavascriptObject(JsApiTestSwift.init(), namespace: nil)
     webview.addJavascriptObject(JsApiTestSwift.init(), namespace: "swift")//增加命名空间, JS在调用的时候可以用 swift.methodName 方便管理功能模块可增强阅读
 }

调用Javascript API

```
// MARK: - 原生调用JS
private func nativeCallJS() {
    
    //原生调用js的addValue方法, 参数是[3, 4], 返回值是value
    webview.callHandler("addValue", arguments: [3, 4]) { (value) in
        print(value ?? "")
    }
    //拼接字符串
    webview.callHandler("append", arguments: ["I", "love", "you"]) { (value) in
        print(value ?? "")
    }
    //传递json
    let dic: Dictionary = ["name": "weixiang", "sex": "male"]
    let jsonStr: String = dicToString(dic) ?? ""
    webview.callHandler("showJson", arguments: [jsonStr]) { (value) in
        print(value ?? "")
    }
    
    //收到result 为json
    let dic1: Dictionary = ["name": "zhangsan", "sex": "male"]
    let jsonStr1: String = dicToString(dic1) ?? ""
    webview.callHandler("showResult", arguments: [jsonStr1]) { (value) in
        print(value ?? "")  
    }

    webview.callHandler("startTimer") { (value) in
        print(value ?? "")
    }
    
    //带有命名空间的方法
    webview.callHandler("syn.addValue", arguments: [5, 6]) { (value) in
        
        print(value as Any)
    }

    //测试是否js有这个方法
    webview.hasJavascriptMethod("addValue") { (isHas) in
        print(isHas)
    }
    
    //如果H5调用了window.close方法就会监听到
    webview.setJavascriptCloseWindowListener {
        print("监听到关闭H5页面")
    } }

命名空间

命名空间可以帮助你更好的管理API,这在API数量多的时候非常实用,比如在混合应用中。DSBridge (>= v3.0.0) 支持你通过命名空间将API分类管理,并且命名空间支持多级的,不同级之间只需用'.' 分隔即可。

调试模式

在调试模式时,发生一些错误时,将会以弹窗形式提示,并且原生API如果触发异常将不会被自动捕获,因为在调试阶段应该将问题暴露出来。如果调试模式关闭,错误将不会弹窗,并且会自动捕获API触发的异常,防止crash。强烈建议在开发阶段开启调试模式,可以通过如下代码开启调试模式:

webview.setDebugMode(true)

进度回调

通常情况下,调用一个方法结束后会返回一个结果,是一一对应的。但是有时会遇到一次调用需要多次返回的场景,比如在javascript钟调用端上的一个下载文件功能,端上在下载过程中会多次通知javascript进度, 然后javascript将进度信息展示在h5页面上,这是一个典型的一次调用,多次返回的场景,如果使用其它Javascript bridge, 你将会发现要实现这个功能会比较麻烦,而DSBridge本省支持进度回调,你可以非常简单方便的实现一次调用需要多次返回的场景,下面我们实现一个倒计时的例子:

// MARK: - 持续返回进度
    @objc func callProgress( _ args:Dictionary<String, Any> , handler: @escaping JSCallback ){
        print("js调用了原生的callProgress方法")
        feedbankHandler = handler
        valueTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(feedbackValue), userInfo: nil, repeats: true)
        
    }
    //返回进度value
    @objc func feedbackValue() {
        
        if let handler = feedbankHandler {
            if value > 0{
                handler(String(value), false)//上传中
                value -= 1
            }else {
                handler(String(value), true)//上传完成
            }
        }
    }

Javascript 弹出框

DSBridge已经实现了 Javascript的弹出框函数(alert/confirm/prompt),这些对话框按钮、标签文字默认都是中文的,如果你想自定义这些文本可以参考 customJavascriptDialogLabelTitles API,如果你不想使用DSBridge实现的对话框,你可以通过设置DSUIDelegate 属性(是WKUIDelegate的代理属性)完全自定义。

另外注意,DSBridge实现的弹出框都是模态的,这会阻塞UI线程,如果你需要非模态的对话框,请参考disableJavascriptDialogBlock API.

WKUIDelegate

DWKWebView 中,请使用DSUIDelegate 代替 UIDelegate , 因为在DWKWebView 内部 UIDelegate已经设置过了,而 DSUIDelegate 正是 UIDelegate 的一个代理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 1.Retrofit2概述 Retrofit框架是Square公司出品的目前非常流行的网络框架.效率高,实现简单,...
    叁鎶阅读 452评论 0 0
  • 一、HTTP协议回顾: 1. HTTP协议概述 WEB浏览器与WEB服务器之间的一问一答的交互过程必须遵循一定的规...
    叁鎶阅读 309评论 0 0
  • 1.SQL语句分类 DDL数据定义语言 用于创建、修改、和删除数据库内的数据结构,如:1.创建和删除数据库(CRE...
    叁鎶阅读 457评论 0 0
  • 公共服务-新对接服务 性能测试 目录 1. 概述.... 3 1.1 背景... 3 1.2 目标... 3 1....
    大树_20e9阅读 235评论 0 0
  • 乡村短工族多是60岁左右的村民,还有少数超过70岁的。他们的子女都成家立业,家里的土地都流转给粮食种植大户,平时种...
    桑榆时光阅读 593评论 4 3