混合开发_混合开发框架 - CSDN
精华内容
参与话题
  • 混合开发

    2020-04-08 10:37:53
    混合开发三类App: 一. NativeApp(原生APP) ​ 纯工具类APP ​ 特点? ​ 开发:由Native人员进行开发的 安卓(Android) 苹果(IOS) ​ 语言:Android(Java+XML) IOS(Objective-c / Swift + XML) ​ 更新...

    混合开发三类App:

    • 1、Native App (原生App)
    • 2、Web App
    • 3、Hybrid App

    一. NativeApp(原生APP)

    纯工具类APP  
    
    ​		特点?
    		开发:Android、IOS工程师开发,
    	        Android:java,xml  配置 java jdk  , Android sdk   eclipse编辑器
    	        IOS:xml,Objective-C/swift,  mac,Imac机上    XCODE
    
    ​			更新维护:版本更新、打补丁包   都得需要用户从app store里面进行下载
    
    ​			使用:必须去app-store里面进行下载更新才能使用软件
    	特点和优势:
    			1、流畅度较高
    			2、对网络的依赖性不强,在没有网络的情况下也可能使用部分功能
    			3、可以调用设备的原生功能
    ​	缺点:
    			不能跨平台开发   必须开发两套代码(Android+IOS)
    
    
    			开发成本
    			        开发成本较高,因为需要分开开发,不能跨平台开发,而且开发周期长,
    			        使用成本较高,因为需要下载安装,话费流量,并长期占用手机的内存
    			        更新维护成本高
    			
    		
    

    二. WebApp(移动M站)

    特点:(凡是可以在移动端浏览器里面打开的网站都称之为WebApp)
    使用:无需下载  直接通过用户的手机浏览器打开使用即可
    更新维护:直接无痕更新(需要注意浏览器缓存问题   缓存的产生是基于文件的路径)
    开发: web前端开发工程师
          使用HTML5+CSS3+js,mac、pc上开发
          更新维护成本低
    
    开发成本:
            开发成本较低,可以实现跨域平台,开发周期短(比较于原生)
            使用成本低,不需要下载安装,通过浏览器空间
    
    特点和优势
            1、用户粘度低
            2、流畅度较低
            3、对网络的依赖性强
            4、不能访问设备的原生功能!因为浏览器的安装级别限制
            (同源策略、不能调用设备的原生功能及文件系统)
    缺点:不稳定 流畅度低  用户体验差   不能调用原生设备 
    

    三. Hybrid App(混合App)

    混合开发的app其实从根本上的技术就是在原生的壳子、界面里嵌入H5页面来实现功能
    
    先决技术:H5页面是可以嵌入到原生的webview中的
    开发模式:
    
    1、原生主导
    
        这是最主流的一种方式,也就是说其实现在市场上的应用已经很少有春原生的了而是大多采用了混合开发的模式,一般都是原生主导的,也就是在某个界面中去嵌入h5页面
    
        区分方式:
                    1.长按文字看是否被选中,如果能选中肯定是嵌入的H5页面
                    
                    2.安卓打开开发模式,手机上就会出现很多的线条,线条包裹起来的就是原生的元素
    
                 为什么要这么做:
                    借助H5页面的跨平台属性来降低开发成本。而且,因为内嵌应用电影、外卖,他们的webapp已经存在了,所以可以直接将webapp的页面嵌入进来
    
                什么样的页面适合去嵌入H5页面
                    布局复杂,逻辑简单,经常更新卫华的,比如详情、部分列表等等都适合嵌入H5页面的方式
    
            1.js判断操作系统
                 html中的window.navigator.userAng   
                    
                    
            2.js与native通信
                   native与js交互
                        1.ios可以调用window下面的方法
                                
                                当跳转详情的时候,详情界面就可以调用里面H5页面的JSBridge的方法来传递参数
                        2.页面中发送所有的网络请求,webview
    
                                一把都是用用iframe标签来发送请求,也就是,事先定义号一个url,作为通信的地址,然后创建iframe去发送这个请求 
                        
    
    2、H5主导的模式
    
    
            纯H5开发工程师借助一些工具去搭建native的外壳,这个应用的内部都是H5页面构成
    
        这种开发模式主要以来的是工具,(打包应用、调用设备原生功能的能力)
                        现有的技术栈
                            1、phoneggap(打包调试) + cordova(调用设备原生功能)
                
                            2、DCLOUD/APICLOUD
                                    
                            3、ReactNative/weex(使用类似H5技术开发,但是开发出来的native app)
    
                        
    
                使用DCLOUD产品开发混合APP
                        
                        HBUILDER可以进行应用的开发、调试、打包
                        MUI是一个高效的前端框架,里面继承了很多native的效果
    
    
                  H5+RUNTIE  用到调用设备原生功能的工具
    
                  1、Hbuilder可以创建移动APP(hybrid app)
    
                    2、在真机上进行应用的调试,必须保证手机能够连接上电脑
        
                    Andriod:
                    IOS:itunes   itools
                    
                    依靠基座来运行,第一次会给手机安装一个基座
    
    

    
    是一个app壳内嵌一个html兼容各种设备,减少发版频率,节约开发成本
    通过jsBright操作底层操作权限
    Hybrid一般分为两类,
        1)放在远程,应用变得非常小,服务器更新及时更新,使用必须联网
        2)打包放在自己app内,使用不需要了联网,下载包变大,不能立即更新
    

    混合应用开发:

    • 1.微信公众号:通过jssdk连接native和web

    • 2.微信小程序:内置框架连接native和web

    • 3.普通原生和web交互:jsBridge

    意义:更好地使用第三方平台,更灵活的技术方案选型,具备搭建平台和输出服务的能力

    • jsbridge是实现native端和web端的双向通信的一种机制,通过约定进行通信
      混合开发主流框架
    1.web渲染:cordova(前身phoneGap)
    2.原生渲染:react native .weex
    3.混合开发:微信小程序
    
    • jsbrige实现原理
      将native端的原生接口封装成javascript接口,将web端的javascript接口封装成原生的接口,实现双向通信
      web调用native的方式有两种:
      1.拦截webview请求中的URL schema
      2.向webview注入jsAPI

    • 方式一:兼容性好,但是不直观,url长度有限制

    //实现:native调用web的时候,web端的方法定义:
    window.方法名=参数=>{方法体}
    //web端调用native的时候,web端的代码:
    window.alert('jsbridge://原生方法?参数="xxx')
    document.location="jsbridge://原生方法?参数=xxx"
    
    • 方式二:简单直观,但是在低版本的手机可能会有兼容性的问题
      web端通过调用注入到js中的原生方法调用native
      native通过注入js调用web
    window.注入到webview的方法.原生方法(参数);
    
    • 支持回调的jsbridge
      webview调用原生的时候会有一个callbackid,返回的时候原生会把callbackid返回找到对应的回调.反之原生调用webview也是类似的
      比如:web调用native时候,web端代码实现如下
    window.JSSDK={
    	getNativeValue(callback){
    		const callID=id++;
    		callbackmap[callID]=callback;
    		nativeBridge.原生方法(callID);
    	}
    	receiveMassage(callID,value){//原生返回值的时候出发的方法
    		if(callbackmap[callID]){
    			callbackmap[callID](value)
    		}
    	}
    }
    调用:
    	widow.getNativeValue(value=>{
    		方法体处理返回值数据
    	})
    
    • native调用web的时候,web端的代码实现:
    widow.JSSDK={
    	getwebText(callbackid){
    		nativeBridge.原生方法(callbackid,'web端的值')
    	}
    }
    
    • jsbridge的开源实现
    DSBridge,可以查看官方文档.原理一样
    
    展开全文
  • 移动端混合开发

    千次阅读 2018-09-28 15:26:18
    到现在做移动混合开发一年多了,做了3个项目,也算是个老手了。虽然只干了一年,但花了很多时间研究,所以感觉至少有2年多的经验。 框架选择:综合上手难度、普及率、资料查询难度等选择了ionic(框架自带整合...

    到现在做移动混合开发一年多了,做了3个项目,也算是个老手了。虽然只干了一年,但花了很多时间研究,所以感觉至少有2年多的经验。

    框架选择:综合上手难度、普及率、资料查询难度等选择了ionic(框架自带整合angularjs+cordova)。官方地址:https://ionicframework.com/docs/

    个人觉得ionic做的页面非常美,没图你说个什么?下面先看看效果

    花了7天做的一个演示demo,地址是http://renrenxiuka.whty.com.cn/app/ICBC/index.html

    是不是被惊艳到了?

    ionic优点:

    1.节约成本、页面好维护

       这是混合开发的共同特点,原生开发ios开发ios的,android开发android的,即耗人力,页面做的也会有差异。混合开发一个人就可以开发跨平台且共用的页面

    2.控件多

      常用的控件官网上都可以查询到,使用方便,比如广告轮播、日期选择等控件。如果控件没有,也可以使用html+css+js的方式实现。如何引用自定义js?后面的博客我会写到。

    3.便捷的插件

     什么是插件?我的理解,插件就是一些封装好的原生功能,在页面上调用。

     ionic采用了cordova来调用原生的功能,自身提供了很多写好的插件,也可以自定义插件,非常方便。

     4.资料查询

      百度搜到关于ionic的资料寥寥无几,要在github上去搜索,在官网上也可查询。

      当需要调整某个控件的颜色或宽度时,在官网上查不到或者觉得慢怎么办?在浏览器上打开调试模式即可看到各种html元素和css样式,找到那个样式再修改即可。

     5.上手简单

      从一个html小白到上手只需几天的时间即可

     6.开发速度快

      用原生写一个list列表,要activity+adapter+viewholder+xml,明明很简单的东西要写一大堆代码,数据请求到了还要notify刷新页面

      现在recyleListview的item分割线甚至还要手动写代码。

      用ionic几分钟可以搞定,页面与ts文件(类似js)数据双向绑定

    ps:还有好多优点,比如丰富的图标库等等

     

    缺点

    1.兼容性

     这是所有混合开发的通病吧,毕竟是基于html

     如ion-list分割线某些机型不显示、某些机型不支持var关键字等,这些都要靠自己慢慢积累。

     2.好像没啥缺点了。。

     

    扫码关注我吧,获取学习视频

    展开全文
  • 混合开发(APP)

    2019-03-04 00:30:35
    1.由于混合开发,(登录app负责),那么在页面完成后对接接口的时候需要传一个token值,都知道token是登录时生成的,此时就需要APP将该值传给我,app大佬表示在url中有给传,截取token传值后token为null,绑到input...

    最近在开发一款APP,在app中嵌入H5,在配合过程中踩了两个小坑。

    1.由于混合开发,(登录app负责),那么在页面完成后对接接口的时候需要传一个token值,都知道token是登录时生成的,此时就需要APP将该值传给我,app大佬表示在url中有给传,截取token传值后token为null,绑到input中显示token有值,那么这是怎么回事。仔细对比发现截取的toke和url中的token有出入,就是因为该token中有特殊字符如:加减乘除等被编码了,获取后没有解码导致。最后还是写了个方法给APP,让其调用该方法时将token值传过来。(当然也可以解码来解决)。

    2.写方法给APP调用,这里必须将该方法挂载到window下APP才能调用。

    如:

    window['getLocationJson']=(jsonData)=>{//用于接收APP传回来的json字符串,然后将其解析为json对象(给APP调用**********需要挂载到window下APP才能调用的到)
      let self=this;
      self.fromApp=JSON.parse(jsonData);
      self.getAppArea=JSON.parse(jsonData).Location;
    }

    3.调用APP的方法(判断安卓和ios)

    if( /(Android)/i.test(navigator.userAgent) ){
      window.android.goLocation('1');    //安卓
    }else{
      window.webkit.messageHandlers.goLocation.postMessage('1');  //Ios
    }

    4.在H5中用a标签或router-link做跳转时安卓不能触发,后面改为点击事件跳转(其实是安卓大佬禁用了重定向)

     

    展开全文
  • 混合 APP 开发(Hybrid App)

    千次阅读 2018-06-01 11:24:18
    混合 App Html5简介 UIWebView 和 WKWebView UIWebView 和 JS 交互 WKWebView 和 JS 交互 JS 调用 Native 相机 一. 混合 APP Hybrid Mobile App 可以理解为通过 Web 网络技术(如 HTML,CSS 和 JavaScript)...

    目录

    • 混合 App
    • Html5简介
    • UIWebView 和 WKWebView
    • UIWebView 和 JS 交互
    • WKWebView 和 JS 交互
    • JS 调用 Native 相机

     

    一. 混合 APP

    Hybrid Mobile App 可以理解为通过 Web 网络技术(如 HTML,CSS 和 JavaScript)与 Native 相结合的混合移动应用程序。

    H5用于大体界面的编写,如:需要一些基本的输入框、单选按钮、普通按钮、以及下拉选择框等。

    CSS3则是主要用于对整体界面细节化的修饰。比如:一个普通按钮,输入框边角默认是直角,那我们可以用CSS来改变其形状。

    还可以用来设置不同的样式。

    JS主要是要跟服务端打交道,实现数据交互。JS中的数据交互,主要以JSON格式跟XML格式这两种格式实现。

    总体来说,H5+CSS3负责界面的搭建,JS负责数据的交互。

     

     

    二. HTML5简介

     

    下面简述一下 Hybrid 的发展史:

     

    1.H5 发布

     

    Html5 是在 2014 年 9 月份正式发布的,这一次的发布做了一个最大的改变就是“从以前的 XML 子集升级成为一个独立集合”。

     

     

     

    2.H5 渗入 Mobile App 开发

     

    Native APP 开发中有一个 webview 的组件(Android 中是 webview,iOS 有 UIWebview和 WKWebview),这个组件可以加载 Html 文件。

    在 H5 大行其道之前,webview 加载的 web 页面很单调(因为只能加载一些静态资源),自从 H5 火了之后,前端猿们开发的 H5 页面在 webview 中的表现不俗使得 H5 开发慢慢渗透到了 Mobile App 开发中来。

     

     

    3.Hybrid 现状

     

    虽然目前已经出现了 RN 和 Weex 这些使用 JS 写 Native App 的技术,但是 Hybrid 仍然没有被淘汰,市面上大多数应用都不同程度的引入了 Web 页面。

     

    三. UIWebView 和 WKWebView

    做浏览器首先要选个好的基础。iOS8提供两类浏览组件:UIWebViewWKWebView

    UIWebView是iOS传统的浏览控件,绝大多数浏览器都采用这个控件作为基础, 如Chrome,Firefox,Safari。UIWebView比较封闭,很多API都不开放,但却一度是唯一的选择。好处是,这个控件使用时间比较长,有很多方案可以参考。

    WKWebView是苹果在iOS8和 OS X Yosemite 中新推出的WebKit中的一个组件。

    它代替了 UIKit 中的UIWebView和AppKit中的WebView,提供了统一的跨双平台 API。支持HTML5的特性, 占用内存可能只有UIWebView的1/3 ~ 1/4, 拥有 60fps 滚动刷新率、内置手势、高效的app和web信息交换通道、和Safari相同的JavaScript引擎, 增加了加载进度属性, 比UIWebView性能更加强大。

    但WKWebView也不是那么完美:如没有控制Cookie的API,  对读取本地html文件的支持也不好等。

     

    四. UIWebView 和 JS 交互

     

    JavaScriptCore介绍

     

    JavaScriptCore 这个库是 Apple 在 iOS 7 之后加入到标准库的,它对 iOS Native 与 JS 做交互调用产生了划时代的影响。

    JavaScriptCore 大体是由 4 个类以及 1 个协议组成的:

     

     

    • JSContext JS 执行上下文,你可以把它理解成 JavaScriptCore 包装出来的 JS 运行的环境。
    • JSValue 是对 JavaScript 值的引用,任何 JS 中的值都可以被包装为一个 JSValue
    • JSManagedValue 是对 JSValue 的包装,加入了“conditional retain”
    • JSVirtualMachine 可以理解为JS 虚拟机JSVirtualMachine中可以创建多个 JSContext 实例他们都是可以独立运行的 JavaScript 执行环境。
    • JSExport 协议:我们可以使用这个协议暴露原生对象,实例方法,类方法,和属性给JavaScript,这样JavaScript就可以调用相关暴露的方法和属性。

     

    Native 调用 JS:

     

    • WebView 直接注入 JS 并执行
    • JavaScriptCore 方法
    WebView 直接注入 JS 并执行
    
    self.webView.stringByEvaluatingJavaScript(from: “jsFuncName()”)
    
    注意:
    这个方法会返回运行 JS 的结果(nullable NSString *),它是一个同步方法,会阻塞当前线程!尽管此方法不被弃用,但最佳做法是使用 WKWebView 类的 evaluateJavaScript:completionHandler:method。注意:
    这个方法会返回运行 JS 的结果(nullable NSString *),它是一个同步方法,会阻塞当前线程!尽管此方法不被弃用,但最佳做法是使用 WKWebView 类的 evaluateJavaScript:completionHandler:method。

     

    JavaScriptCore 方法
    // 导入 JavaScriptCore 库
    
    JavaScriptCore 库提供的 JSValue 类,是对 JavaScript 值的引用。 您可以使用 JSValue 类来转换 JavaScript 和 Objective-C 或 Swift 之间的基本值(如数字和字符串),以便在本机代码和 JavaScript 代码之间传递数据。
    
    Native 代码: 
    self.context = webView.value(forKeyPath: “documentView.webView.mainFrame.javaScriptContext")
    
    let jsValue: JSValue = self.context.objectForKeyedSubscript(“jsFuncName()”)
            jsValue.call(withArguments: ["param1" ,"param2"])
    
    JS 代码: 
    function jsFuncName(param1, param2){
    
    }
    

     

     

     

    JS 调用 Native :

     

    • 拦截 URL 请求
    • Block 方法
    • 模型注入(JavaScriptCore 的 JSExport 协议)
    拦截 URL 请求
    
    用JS 发起一个假的 URL 请求, 然后在 shouldStartLoadWith 代理方法中拦截这次请求, 做出相应处理.
    注意: 
    这里在JS 中自定义一个loadURL 方法发起请求,而不是直接使用 window.location.href
    如果要传递参数, 可以拼接在 URL 上
    
    Native 代码:
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
            if request.url?.scheme == "haleyAction" {
                // to do something
                return false
            }
           return true
     }
            
    JS 代码:
    function loadURL(url) {
        var iFrame;
        iFrame = document.createElement("iframe");
                iFrame.setAttribute("src", url);
                iFrame.setAttribute("style", "display:none;");
                iFrame.setAttribute("height", "0px");
                iFrame.setAttribute("width", "0px");
                iFrame.setAttribute("frameborder", "0");
                document.body.appendChild(iFrame);
                // 发起请求后这个 iFrame 就没用了,所以把它从 dom 上移除掉
                iFrame.parentNode.removeChild(iFrame);
                iFrame = null;
            }
        
            function firstClick() {
                //要传递参数时, 可以拼接在url上
                loadURL("haleyAction://shareClick?title=测试分享的标题&content=测试分享的内容&url=http://www.baidu.com");
            }

     

    Block 方法
    
    使用 block 在js中运行原生代码, 将自动与JavaScript方法建立桥梁
    注意: 这种方法仅仅适用于 OC 的 block, 并不适用于swift中的闭包, 为了公开闭包,      
    我们将进行如下两步操作:
    (1)使用 @convention(block) 属性标记闭包,来建立桥梁成为 OC 中的 block
    (2)在映射 block 到 JavaScript方法调用之前,我们需要 unsafeBitCast 函数将block 转成为 AnyObject
    
    Native 代码:
    // JS调用了无参数swift方法
    let closure1: @convention(block) () ->() = {
                
    }
    self.context.setObject(unsafeBitCast(closure1, to: AnyObject.self),   
    forKeyedSubscript: "test1" as NSCopying & NSObjectProtocol)
    
    // JS调用了有参数swift方法
    let closure2: @convention(block) () ->() = {
                
    }
    self.context.setObject(unsafeBitCast(closure2, to: AnyObject.self), 
    forKeyedSubscript: "test2" as NSCopying & NSObjectProtocol)
    
    JS 代码:
    function JS_Swift1(){
        test1();
    }
    function JS_Swift2(){
        test2('oc','swift');
    }注意: 这种方法仅仅适用于 OC 的 block, 并不适用于swift中的闭包, 为了公开闭包,      
    我们将进行如下两步操作:
    (1)使用 @convention(block) 属性标记闭包,来建立桥梁成为 OC 中的 block
    (2)在映射 block 到 JavaScript方法调用之前,我们需要 unsafeBitCast 函数将block 转成为 AnyObject
    
    Native 代码:
    // JS调用了无参数swift方法
    let closure1: @convention(block) () ->() = {
                
    }
    self.context.setObject(unsafeBitCast(closure1, to: AnyObject.self),   
    forKeyedSubscript: "test1" as NSCopying & NSObjectProtocol)
    
    // JS调用了有参数swift方法
    let closure2: @convention(block) () ->() = {
                
    }
    self.context.setObject(unsafeBitCast(closure2, to: AnyObject.self), 
    forKeyedSubscript: "test2" as NSCopying & NSObjectProtocol)
    
    JS 代码:
    function JS_Swift1(){
        test1();
    }
    function JS_Swift2(){
        test2('oc','swift');
    }

     

     

    模型注入(JavaScriptCore  JSExport 协议)
    
    步骤一: 自定义协议服从 JSExport协议
    可以使用该协议暴露原生对象,实例方法,类方法,和属性给JavaScript,这样JavaScript就可以调用相关暴露的方法和属性。遵守JSExport协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来
    
    注意:
    如果js是多个参数的话  我们代理方法的所有变量前的名字连起来要和js的方法名字一样比如: js方法为  OCModel.showAlertMsg('js title', 'js message’),他有两个参数 那么我们的代理方法 就是把js的方法名 showAlertMsg 任意拆分成两段作为代理方法名
    
    第一个参数的 argumentLabel 用 "_" 隐藏
    @objc protocol JavaScriptSwiftDelegate: JSExport {
    
        func callNoParam()
        
        func showAlert(_ title: String, msg: String)
    }
    
    步骤二: 自定义模型服从自定义协议, 实现协议方法
    
    @objc class JSObjCModel: NSObject, JavaScriptSwiftDelegate {
        weak var controller: UIViewController?
        weak var jsContext: JSContext?
        
        func callNoParam() {
            let jsFunc = self.jsContext?.objectForKeyedSubscript("jsFunc");
            _ = jsFunc?.call(withArguments: []);
        }
        
        func showAlert(_ title: String, msg: String) {
            let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default, handler: nil))
            self.controller?.present(alert, animated: true, completion: nil)
        }
    }
    
    步骤三: 将模型对象注入 JS
    
    // 模型注入
    let model = JSObjCModel()
    model.controller = self
    model.jsContext = context
    // 这一步是将OCModel这个模型注入到JS中,在JS就可以通过OCModel调用我们暴露的方法了
    context.setObject(model, forKeyedSubscript: "OCModel" as NSCopying & NSObjectProtocol)
    let url = Bundle.main.url(forResource: "WebView", withExtension: "html")
    context.evaluateScript(try? String.init(contentsOf: url!, encoding: .utf8))
    context.exceptionHandler = { [unowned self](con, except) in
                self.context.exception = except
    }
    
    JS 代码:
    <div class='btn-button' onclick="OCModel.callNoParam()">JS调用Native方式三无参</div>
    <div class='btn-button' onclick="OCModel.showAlertMsg('js title', 'js message’)">JS调用Native方式三有参</div>(JavaScriptCore  JSExport 协议)
    
    步骤一: 自定义协议服从 JSExport协议
    可以使用该协议暴露原生对象,实例方法,类方法,和属性给JavaScript,这样JavaScript就可以调用相关暴露的方法和属性。遵守JSExport协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来
    
    注意:
    如果js是多个参数的话  我们代理方法的所有变量前的名字连起来要和js的方法名字一样比如: js方法为  OCModel.showAlertMsg('js title', 'js message’),他有两个参数 那么我们的代理方法 就是把js的方法名 showAlertMsg 任意拆分成两段作为代理方法名
    
    第一个参数的 argumentLabel 用 "_" 隐藏
    @objc protocol JavaScriptSwiftDelegate: JSExport {
    
        func callNoParam()
        
        func showAlert(_ title: String, msg: String)
    }
    
    步骤二: 自定义模型服从自定义协议, 实现协议方法
    
    @objc class JSObjCModel: NSObject, JavaScriptSwiftDelegate {
        weak var controller: UIViewController?
        weak var jsContext: JSContext?
        
        func callNoParam() {
            let jsFunc = self.jsContext?.objectForKeyedSubscript("jsFunc");
            _ = jsFunc?.call(withArguments: []);
        }
        
        func showAlert(_ title: String, msg: String) {
            let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "确定", style: .default, handler: nil))
            self.controller?.present(alert, animated: true, completion: nil)
        }
    }
    
    步骤三: 将模型对象注入 JS
    
    // 模型注入
    let model = JSObjCModel()
    model.controller = self
    model.jsContext = context
    // 这一步是将OCModel这个模型注入到JS中,在JS就可以通过OCModel调用我们暴露的方法了
    context.setObject(model, forKeyedSubscript: "OCModel" as NSCopying & NSObjectProtocol)
    let url = Bundle.main.url(forResource: "WebView", withExtension: "html")
    context.evaluateScript(try? String.init(contentsOf: url!, encoding: .utf8))
    context.exceptionHandler = { [unowned self](con, except) in
                self.context.exception = except
    }
    
    JS 代码:
    <div class='btn-button' οnclick="OCModel.callNoParam()">JS调用Native方式三无参</div>
    <div class='btn-button' οnclick="OCModel.showAlertMsg('js title', 'js message’)">JS调用Native方式三有参</div>

     

    五. WKWebView JS 交互

     

    WKWebView 的配置
    
    //导入 WebKit
    //创建配置类
    let confirgure = WKWebViewConfiguration()
                 
    //WKUserContentController: 内容交互控制器
    confirgure.userContentController = WKUserContentController()
            
    //创建WKWebView
    wkWebView = WKWebView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height), configuration: confirgure)
            
    //配置代理
    wkWebView.navigationDelegate = self as WKNavigationDelegate
    wkWebView.uiDelegate = self as WKUIDelegate

     

    Native 调用 JS

     

    • WebView 直接注入 JS 并执行

     

    不同于 UIWebView,WKWebView 注入并执行 JS 的方法不会阻塞当前线程。因为考虑到 webview 加载的 web content 内 JS 代码不一定经过验证,如果阻塞线程可能会挂起 App。
    
    self.wkWebView.evaluateJavaScript(“jsFuncName()") { (result, error) in
                print(result, error)
    }
    
    注意: 
    方法不会阻塞线程,而且它的回调代码块总是在主线程中运行。注意: 
    方法不会阻塞线程,而且它的回调代码块总是在主线程中运行。

     

    JS 调用 Native 

     

    • 拦截 URL 请求
    • Webkit 的 WKUIDelegate协议
    • 模型注入(Webkit 的 WKScriptMessageHandler协议)
       
    拦截 URL 请求
    拦截请求的代理方法为 WebKit 中 WKNavigationDelegate 协议的
    
     func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: ) 方法
    
    , 其它同 WebView

     

    Webkit 的 WKUIDelegate协议
    
    WKUIDelegate 协议包含一些函数用来监听 web JS 想要显示 alert 或 confirm 时触发。我们如果在 WKWebView 中加载一个 web 并且想要 web JS 的 alert 或 confirm 正常弹出,就需要实现对应的代理方法。
    
    以JS 弹出Confirm 为例, 下面是在 WKUIDelegate 监听 web 要显示 confirm 的代理方法中用 Native UIAlertController 替代 JS 中的 confirm 显示的 例子: 
    
    //通过 message 得到JS 端所传的数据,在 ios 端显示原生 alert 得到 true/false 后通过 completionHandler 回调给 JS
    
    Native 代码:
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
            let alert = UIAlertController(title: "Confirm", message: message, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) -> Void in
                completionHandler(true)
            }))
            alert.addAction(UIAlertAction(title: "cancel", style: .cancel, handler: { (_) -> Void in
                completionHandler(false)
            }))
            self.present(alert, animated: true, completion: nil)
    }
    
    JS 代码:
    function callJsConfirm() {
            if (confirm('confirm', 'Objective-C call js to show confirm')) {
                d ocument.getElementById('jsParamFuncSpan').innerHTML = 'true';
            }else {
                 document.getElementById('jsParamFuncSpan').innerHTML = 'false';
            }
    }
    

     

    模型注入(Webkit 的 WKScriptMessageHandler协议)
    
    注意: 
    对象注入写在 viewWillAppear 中, 防止循环引用
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            //注入对象名称 APPModel, 当 JS 通过 APPModel 调用时, 可以在 WKScriptMessageHandler 代理方法中接收到
            wkWebView.configuration.userContentController.add(self, name: "APPModel")
        }
        
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            wkWebView.configuration.userContentController.removeScriptMessageHandler(forName: "APPModel")
              }
    
    JS 通过 AppModel 给 Native 发送数据,会在该方法中收到
    JS调用iOS的部分, 都只能在此处使用, 我们也可以注入多个名称(JS对象), 用于区分功能
    
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == "APPModel" {
                //传递的参数只支持NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull类型
                let alert = UIAlertController(title: "MessageHandler", message: message.name, preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) -> Void in
                    
                }))
                self.present(alert, animated: true, completion: nil)
            }
        }
    
    JS 代码:
    function messageHandlers() {
            //APPModel 是我们注入的对象
            window.webkit.messageHandlers.APPModel.postMessage({body: 'messageHandlers'});
    }
    注意: 
    对象注入写在 viewWillAppear 中, 防止循环引用
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            //注入对象名称 APPModel, 当 JS 通过 APPModel 调用时, 可以在 WKScriptMessageHandler 代理方法中接收到
            wkWebView.configuration.userContentController.add(self, name: "APPModel")
        }
        
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            wkWebView.configuration.userContentController.removeScriptMessageHandler(forName: "APPModel")
              }
    
    JS 通过 AppModel 给 Native 发送数据,会在该方法中收到
    JS调用iOS的部分, 都只能在此处使用, 我们也可以注入多个名称(JS对象), 用于区分功能
    
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
            if message.name == "APPModel" {
                //传递的参数只支持NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull类型
                let alert = UIAlertController(title: "MessageHandler", message: message.name, preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (_) -> Void in
                    
                }))
                self.present(alert, animated: true, completion: nil)
            }
        }
    
    JS 代码:
    function messageHandlers() {
            //APPModel 是我们注入的对象
            window.webkit.messageHandlers.APPModel.postMessage({body: 'messageHandlers'});
    }
    

     

    六. JS 通过 Native 调用iOS 硬件(相机)

    JS 调用 iOS 硬件, 本质上还是通过以上介绍的 JS 调用 Native 方法调用 Native接口,

    再由 Native 调用本地硬件, 具体实现看 demo , 这里不再赘述.

     

     

    参考链接:

     

    拦截 URL:

    https://www.jianshu.com/p/d19689e0ed83

    https://blog.csdn.net/wanglei0918/article/details/78141890

    WKWebView 和 JS 交互:

    https://github.com/marcuswestin/WebViewJavascriptBridge

    http://www.cocoachina.com/ios/20171024/20895.html

    https://blog.csdn.net/baihuaxiu123/article/details/51674726

    WebView 和 JS 交互:

    https://www.jianshu.com/p/c11f9766f8d5

    https://www.jianshu.com/p/8f3c47c24e29

    https://blog.csdn.net/longshihua/article/details/51645575

     

    Github地址: 点击打开链接

    https://github.com/LeeJoey77/WebView_H5Demo.git
    
     
    https://github.com/LeeJoey77/WebView_H5Demo.gi

     

     

     

     

     

     

     

     

    展开全文
  • Android Hybrid混合开发

    2020-10-26 11:43:22
    关于混合开发常问道的问题: Android如何嵌套h5页面? h5一般调用哪些Android哪些接口功能? Android如何调用网页(js)功能? 问题1.ndroid如何嵌套h5页面答案: 当我们用vue开发完项目,执行nmp run build打包...
  • 谈谈App混合开发

    千次阅读 2019-05-24 10:56:07
    混合开发的App(Hybrid App)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html 5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更...
  • 5个好用的混合式App开发工具

    千次阅读 2015-09-08 17:11:10
    在残酷的移动互联网竞争环境下, HTML5技术一直受到各方关注,“HTML5颠覆原生 App”的争论也从未...于是,一个一直被提及但是从没有占据过统治地位的概念又一次走进了移动开发者们的视野,那就是跨平台开发。 AD:
  • Hybrid APP混合开发的一些经验和总结

    万次阅读 多人点赞 2017-03-31 11:14:29
    由于业务需要,接触到一个Hybrid APP混合开发的项目。当时是第一次接触混合开发,有一些经验和总结,欢迎各位一起交流学习~ 1、混合开发概述 Hybrid App主要以JS+Native两者相互调用为主,从开发层面实现“一次...
  • 移动端app开发,原生开发与混合开发的区别

    万次阅读 多人点赞 2019-09-26 18:47:01
    目前市场上主流的APP分为三种:原生APP、Web APP(即HTML5)和混合APP三种,相对应的定制开发就是原生开发、H5开发和混合开发。那么这三种开发模式究竟有何不同呢?下面我们就分别从这三者各自的优劣势来区分比较吧...
  • React Native Android混合开发实用教程

    千次阅读 2018-08-28 23:01:18
    在React Native的应用场景中,有时候一个APP只有部分页面是由React Native实现的,比如:我们常用的携程App,它的首页下的很多模块都是由React Native实现的,这种开发模式被称为混合开发混合开发的一些其他应用...
  • Android混合开发的入门和方案

    万次阅读 2016-11-18 20:53:14
    讲解了怎么开始入门混合开发一个Android hybrid应用,和说明了WebView的工作原理,利用JsBridge加速开发进度和JsBridge的工作原理,在JsBridge的基础上加强前段与native的交流的灵活性,最后提出了一个hybrid应用的...
  • 目前市场上主流的APP分为三种:原生APP、Web APP(即HTML5)和混合APP三种,相对应的定制开发就是原生开发、H5开发和混合开发。那么这三种开发模式究竟有何不同呢?下面我们就分别从这三者各自的优劣势来区分比较吧...
  • Android混合开发

    2017-04-11 15:51:19
    原文地址:写的很好 膜拜!
  • Hybird APP (混合开发)简介

    万次阅读 2018-04-17 14:38:16
    写了几个 APP,最初是打算用纯 Native 的,可是我自身的 Android...还好有前辈指点了一下,可以采用 Hybrid APP(混合开发),一路磕磕绊绊的完成了项目。看了不少资料,从菜鸟的角度来总结下 Hybrid APP(混合开发)。
  • 谈谈Android App混合开发

    万次阅读 2017-06-09 16:09:13
    混合开发的App(Hybrid App)就是在一个App中内嵌一个轻量级的浏览器,一部分原生的功能改为Html 5来开发,这部分功能不仅能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,让用户的体验更...
  • 入门 Kotlin 和 Java 混合开发

    千次阅读 2018-08-15 14:44:28
    一、前沿 如果你学习过其他的编程语言,你就会发现 Java 的语法很是哆嗦,可是我们为什么没有放弃 Java 这门编程语言呢?因为 JVM 是一个非常好的平台,而且 Java 程序员目前在中国所占的比重实在是太高了。...
  • iOS混合开发调试秘籍

    千次阅读 2017-03-02 19:40:06
    在进行混合开发的时候(H5&&iOS),进行联合调试很是让我们开发者头疼,为了锁定问题所在,H5小伙伴没少打alert,我们这边也没少打log日志,很是麻烦,下面给大家说一下我的新发现。轻松解决混合开发中的调试问题。1...
  • Flutter与原生混合开发实现过程

    千次阅读 2019-09-13 13:13:46
    本篇博客不讲原理,只讲实现方法,从0到1实现 Flutter 和原生的混合开发。将会新建一个 Android 原生项目,取名叫 AndroidDemo,然后新建一个 FlutterModule 项目,取名为 flutter_module,两个项目都放在 flutter_...
  • 随着小程序支持HTTPS网页嵌入,小程序与H5页面混合开发将是大势所趋,就如同现在APP开发一样亦是混合开发,部分功能使用H5页面实现,至少有如下2个好处: 1)、解决小程序审核等待问题:只要修改WEB页面即可,无需...
  • vue 混合开发 和 组件

    千次阅读 2018-01-26 21:59:31
    vue 混合开发 和 组件 刚开始接触vue时,没有什么组件意识,对于混合开发还没接触,一个页面的所有逻辑都写在一个.vue文件中,逻辑比较简单的还比较好,没有很明显的差别,但是对于逻辑比较复杂的,问题就出现了,...
1 2 3 4 5 ... 20
收藏数 239,092
精华内容 95,636
关键字:

混合开发