「混合开发」H5与原生App交互流程方案全面解析

目录

内嵌H5调用iOS内的方法

[1. 背景](#1. 背景)

[2. 解决方案](#2. 解决方案)

[2.1 创建WebView](#2.1 创建WebView)

[2.2 注册原生方法](#2.2 注册原生方法)

[2.3 H5调用原生方法](#2.3 H5调用原生方法)

[3. 序列图](#3. 序列图)

[H5 调用 Android:详细指南](#H5 调用 Android:详细指南)

整体流程

每一步的详细说明

步骤1:在Android项目中设置WebView

步骤2:定义JavaScript接口

步骤3:加载H5网页

步骤4:在H5中调用Android方法

步骤5:处理Android的方法返回值

状态图

序列图

h5页面运行环境判断

一、先上代码:js封装

二、js封装代码的一些说明

三、配合vue封装个自定义指令


1.本文将介绍如何在H5页面中调用iOS原生方法,实现混合开发的功能。

2.本文将介绍如何在H5页面中调用Android原生方法,实现混合开发的功能。

  1. h5页面运行环境判断

为什么H5能直接调用?

  • 环境注入:App启动WebView时,会向JS环境注入特定对象:

    • Android:注入window.Android对象

    • iOS:注入window.webkit.messageHandlers容器

  • 协议约定:双方提前约定方法名和参数格式

  • 桥梁作用:WebView充当通信代理,转发JS调用到原生代码

内嵌H5调用iOS内的方法

1. 背景

随着移动互联网的快速发展,原生应用与H5页面的结合成为了一种常见的开发方式。而在一些特定的场景中,我们需要在H5页面中调用iOS原生方法来实现一些功能,比如调用相册、获取地理位置等等。

2. 解决方案

在iOS中,我们可以通过JavaScriptCore框架来实现H5与iOS原生方法的交互。下面将介绍具体的实现步骤。

2.1 创建WebView

首先,我们需要在iOS原生应用中创建一个WebView,用于加载H5页面。可以使用WKWebViewUIWebView来实现,这里以WKWebView为例。

复制代码
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler {
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 加载H5页面
        if let url = Bundle.main.url(forResource: "index", withExtension: "html") {
            webView.loadFileURL(url, allowingReadAccessTo: url.deletingLastPathComponent())
        }
        
        // 注册JavaScript与原生方法的消息通信
        webView.configuration.userContentController.add(self, name: "nativeMethod")
    }
}
2.2 注册原生方法

在iOS原生应用中,我们需要注册一些原生方法,供H5页面调用。可以通过WKScriptMessageHandler协议来实现。

复制代码
extension ViewController {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "nativeMethod" {
            let body = message.body as? [String: Any]
            let method = body?["method"] as? String
            let params = body?["params"] as? [String: Any]
            
            if method == "openCamera" {
                openCamera()
            } else if method == "getLocation" {
                getLocation()
            }
        }
    }
    
    func openCamera() {
        // 打开相机逻辑
    }
    
    func getLocation() {
        // 获取地理位置逻辑
    }
}
2.3 H5调用原生方法

在H5页面中,我们可以通过JavaScript代码来调用iOS原生方法。可以使用window.webkit.messageHandlers对象来发送消息给iOS原生应用。

复制代码
function callNativeMethod(method, params) {
    window.webkit.messageHandlers.nativeMethod.postMessage({ method: method, params: params });
}

// 调用原生相机方法示例
callNativeMethod("openCamera");

// 调用原生地理位置方法示例
callNativeMethod("getLocation");

3. 序列图

下面是一个使用Sequence Diagram插件绘制的序列图,说明了H5调用iOS原生方法的流程。

iOS原生应用H5页面iOS原生应用H5页面调用原生方法执行原生方法

H5 调用 Android:详细指南

在现代的应用开发中,H5(HTML5)和原生Android应用之间的交互变得越来越重要。通过这种交互,开发者可以充分利用两者的优势,提高用户体验。在本文中,我将为你详细介绍如何实现H5调用Android的过程,包括每一步的详细步骤、代码示例以及图示表示。

整体流程

下面是H5调用Android的流程表:

步骤 描述
1 在Android项目中设置WebView
2 定义JavaScript接口
3 加载H5网页
4 在H5中调用Android方法
5 处理Android的方法返回值

每一步的详细说明

步骤1:在Android项目中设置WebView

首先,在你的Android项目中创建一个WebView,以便加载H5页面。

复制代码
// MainActivity.java
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 找到WebView组件
        webView = findViewById(R.id.webView);
        // 允许JavaScript执行
        webView.getSettings().setJavaScriptEnabled(true);
        // 加载H5页面
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("file:///android_asset/index.html"); //加载本地H5页面
    }
}

代码说明:

  • getSettings().setJavaScriptEnabled(true);:允许在WebView中执行JavaScript,这样H5能够调用安卓的方法。
  • loadUrl(...):加载你的H5页面,可以是本地文件或网络地址。
步骤2:定义JavaScript接口

你需要定义一个JavaScript接口,使H5能够调用Android的方法。

复制代码
import android.webkit.JavascriptInterface;

public class WebAppInterface {
    MainActivity mActivity;

    WebAppInterface(MainActivity c) {
        mActivity = c;
    }

    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(mActivity, toast, Toast.LENGTH_SHORT).show();
    }
}

// 在MainActivity中
webView.addJavascriptInterface(new WebAppInterface(this), "Android");

代码说明:

  • @JavascriptInterface注解让H5中的JavaScript可以访问Android的方法。
  • showToast(String toast)是供H5调用的一个示例方法。
步骤3:加载H5网页

H5页面的内容可以是一个简单的HTML文件,比如index.html

复制代码
<!DOCTYPE html>
<html>
<head>
    <title>H5 to Android</title>
    <script type="text/javascript">
        function callAndroid() {
            // 调用Android方法
            Android.showToast("Hello from H5!");
        }
    </script>
</head>
<body>
    H5调用Android
    <button onclick="callAndroid()">调用Android</button>
</body>
</html>

代码说明:

  • onclick="callAndroid()":当用户点击按钮时,将调用callAndroid函数,该函数将通过Android接口调用showToast方法。
步骤4:在H5中调用Android方法

之前的代码已经涵盖了这一部分。用户点击按钮时,H5会调用Android的showToast方法。

步骤5:处理Android的方法返回值

如果你的Android方法需要返回值,确保你在JavaScript接口中做相应的处理。例如,假设你要在Android中返回当前时间:

复制代码
@JavascriptInterface
public String getCurrentTime() {
    return java.text.DateFormat.getDateTimeInstance().format(new java.util.Date());
}

然后在H5中调用它:

复制代码
function fetchTime() {
    // 获取当前时间并显示
    var currentTime = Android.getCurrentTime();
    alert("Current Time: " + currentTime);
}

状态图

以下是H5与Android之间的状态转移图示,描述了用户如何触发操作:

H5页面调用AndroidAndroid执行返回结果

序列图

下面是H5调用Android的序列图:

AndroidH5AndroidH5调用showToast("Hello from H5!")显示Toast消息

h5页面运行环境判断

  • 判断h5页面所处的运行环境,以便针对不同的环境做兼容性或差异化处理;
  • 由于很多时候需要一进页面就第一时间做处理,所以异步的判断方法都不予考虑,必须是能实时获取的;
  • 那么自然的,判断UA是最好、最方便的方式。

一、先上代码:js封装

platform.js:

复制代码
const ua = window.navigator.userAgent.toLowerCase()

// android平台
const isAndroid = (() => {
  return /Android|Adr/i.test(ua)
})()

// ios平台
const isIos = (() => {
  return /iPhone|iPod|iPad/i.test(ua)
})()

// 微信生态
const isWechat = (() => {
  return /MicroMessenger/i.test(ua)
})()

// 微信小程序
const isWxmp = (() => {
  return /miniProgram/i.test(ua) || window.__wxjs_environment === 'miniprogram'
})()

// 钉钉环境
const isDingding = (() => {
  return /DingTalk/i.test(ua)
})()

// 自家的android客户端
const isInnerAdr = (() => {
  return isAndroid && /dianyidian/i.test(ua)
})()

// 自家的ios客户端
const isInnerIos = (() => {
  return isIos && /dianyidian/i.test(ua)
})()

// 自家的app客户端
const isInnerApp = (() => {
  return isInnerAdr || isInnerIos
})()

// 站内
const isInner = (() => {
  return isInnerAdr || isInnerIos || isWxmp
})()

// 站外
const isOuter = (() => {
  return !isInner
})()

export default {
  isAndroid,
  isIos,
  isWechat,
  isWxmp,
  isDingding,
  isInnerAdr,
  isInnerIos,
  isInnerApp,
  isInner,
  isOuter
}

二、js封装代码的一些说明

  • 微信生态,包括微信小程序、微信内置浏览器、微信公众号等

  • 针对hybrid混合开发模式中的webview内嵌h5页,需要判断自家的客户端,这时需要让客户端开发人员修改webview的UA,添加上特殊的UA标识,用来给h5做判断,比如我这里的标识就是dianyidian。

  • 关于站内站外的划分因人而异,自己决定,使用方便就好。

  • 导出的每一个属性值都是boolean类型,true或false。

  • 在自家ios客户端接入阿里百川后发现UA被莫名的覆盖了,这种情况可以额外加个判断处理:

    // 自家ios客户端
    const isInnerIos = (() => {
    if (isIos && /baichuan/i.test(ua)) {
    // 兼容ios客户端跳转阿里百川授权后再打开webview的userAgent被百川覆盖的问题
    return true
    }
    return isIos && /dianyidian/i.test(ua)
    })()

  • 以上都是实际项目中经过考验了的,放心使用。

三、配合vue封装个自定义指令

  • 指令作用:根据页面运行环境给元素添加相应的class类名,这样就可以在css样式里很方便的对不同环境做不同的处理。

  • 指令封装:

    // 先引入上述封装的platform.js
    import platform from '@/utils/platform'

    export default {
    bind (el) {
    Object.keys(platform).forEach(v => {
    if (platform[v]) {
    el.classList.add(v)
    }
    })
    }
    }

  • 使用示例:

    <template>
    使用示例
    </template> <script> import platforms from '@/directive/platforms/index'

    export default {
    directives: { platforms }
    }
    </script>

    <style lang='less' scoped> .demo { color: red; &.isAdr { // 安卓平台下的自定义样式处理 } &.isIos { // ios平台下的自定义样式处理 } &.isWxmp { // 微信小程序下的自定义样式处理 } // 其他环境下也一样,任性的加...... } </style>
相关推荐
大猩猩爱分享2 小时前
Mac安装docker desktop
macos·docker
伊织code2 小时前
pmset - 控制 macOS 系统电源、睡眠、唤醒与节能
macos·命令·电源·睡眠·节能·唤醒·pmset
serve the people3 小时前
在mac上安装sh脚本文件
macos
莫邪博客3 小时前
解决蓝牙MAC 地址倒序问题
macos
草明3 小时前
macOS 查看当前命令行的ruby的安装目录
开发语言·macos·ruby
五阿哥爱跳舞3 小时前
MAC无法 ping 通github 系列主页
macos
I烟雨云渊T18 小时前
2025年的WWDC所更新的内容
macos·ios·wwdc
Fatbobman(东坡肘子)18 小时前
WWDC 2025 开发者特辑 | 肘子的 Swift 周报 #088
开发语言·macos·ios·swiftui·ai编程·swift·wwdc