场景描述: 公司经常为了加快项目的推进,常常需要咱们前端写一些H5页面嵌入到原生的APP开发当中去,例如
调用设备的摄像头、地理位置、文件系统、显示原生的对话框、提示框等,以提供更好的用户体验。
疑难问题:如何和安卓/IOS产生交互…
前言:
uni.getSystemInfoSync().platform
:Uni-app 框架中用于获取当前运行平台信息的同步方法。它返回一个字符串,表示当前应用运行的操作系统平台。
uni.getSystemInfoSync().platform
获取平台信息
返回值可以是以下几种之一:
android:表示当前设备是安卓系统。
ios:表示当前设备是iOS系统。
devtools:表示当前是在开发者工具中运行。
其他平台:如微信小程序、H5等,具体取决于Uni-app支持的平台。
安卓与H5混合开发流程
- 安卓
WebView
注入
window.安卓提供方法名
调用 Android 原生方法并传递参数(如 android.args)是通过 WebView 和 JavaScript Bridge 实现的。
安卓人员在WebView
中注入一个 Java 对象(即代码中的Android
),并通过addJavascriptInterface
方法将该对象暴露给JavaScript
环境。
// 在 Android 原生代码中设置 WebView 并注入 JavaScript Interface
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
// 创建一个 Java 类来处理 JavaScript 的调用
webView.addJavascriptInterface(new WebAppInterface(this), "Android"); // 安卓类的名称Android
public class WebAppInterface {
Context mContext;
WebAppInterface(Context c) {
mContext = c;
}
@JavascriptInterface // 该类包含需要暴露给 JavaScript 的方法,
public String doSomething(String args) { //方法名称
// 处理传入的参数并返回结果
return "Result from Android: " + args;
}
}
- 前端
JavaScript
调用
window.className
[android.name
方法名 ] (android.args
传递参数)
if (window.rentalAndroid) {
const result = window.rentalAndroid.doSomething('someArgument'); // 调用方法类并传参
console.log(result); // 输出 "Result from Android: someArgument"
} else {
console.error('获取 android 事件对象失败');
}
IOS与H5混合开发流程
- IOS设置
WKWebView
和WKScriptMessageHandler
首先,在 iOS 原生代码中设置WKWebView
并注册WKScriptMessageHandler
,以便处理来自JavaScript
的消息。
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// 创建 WKWebView 配置
let config = WKWebViewConfiguration()
config.userContentController.add(self, name: "nativeHandler")
// 初始化 WKWebView
webView = WKWebView(frame: self.view.frame, configuration: config)
self.view.addSubview(webView)
// 加载 H5 页面
if let url = URL(string: "https://example.com") { // H5页面链接
let request = URLRequest(url: url)
webView.load(request)
}
}
// 处理来自 JavaScript 的消息
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "nativeHandler" { //IOS定义方法名称
if let args = message.body as? [String: Any] {
// 处理传入的参数
handleNativeCall(args: args)
}
}
}
// 处理具体的原生方法调用
func handleNativeCall(args: [String: Any]) {
if let action = args["action"] as? String {
switch action {
case "doSomething": // 定义类别
if let param = args["param"] as? String {
// 处理参数并执行相应操作
print("Received parameter: \(param)")
// 返回结果给 JavaScript
let result = "Result from iOS: \(param)"
webView.evaluateJavaScript("window.postMessage('\(result)', '*')")
}
default:
print("Unknown action: \(action)")
}
}
}
}
- 前端
JavaScript
调用
在前端代码中,你可以通过window.webkit.messageHandlers
发送消息到原生代码。
const messageBody = {
action: ios.name,
param: ios.args || null
};
// 发送消息到原生代码
window.webkit.messageHandlers.nativeHandler.postMessage(messageBody);
使用js封装调用安卓、IOS方法
platformHandler
是一个封装方法,接收一个对象参数,包含以下属性:
android: 对应安卓平台的方法配置。
ios: 对应iOS平台的方法配置。
success: 成功回调函数。
fail: 失败回调函数。
如果是Android平台:
检查是否提供了有效的Android方法配置 (android.name
)。
使用window.rentalAndroid
调用Android原生方法,并传递参数 (android.args
)。
如果成功调用,将结果传递给 success 回调;否则,显示错误提示并执行 fail 回调。
如果是iOS平台:
检查是否提供了有效的iOS方法配置 (ios.name
)。
使用window.webkit.messageHandlers
调用iOS原生方法,并传递参数 (ios.args
)。
如果成功调用,执行 success 回调;否则,显示错误提示并执行 fail 回调。
1. 封装方法+平台判断
const platform = uni.getSystemInfoSync().platform; // 获取平台信息
// 判断平台
function isIOS() {
return platform === 'ios';
}
function isAndroid() {
return platform === 'android';
}
function platformHandler({
android,
ios,
success,
fail
}) {
if (isIOS()) {
// console.log('调用ios函数')
if (!ios || !ios.name) return $mHelper.toast('未添加相应的ios方法');
if (window.webkit && window.webkit.messageHandlers) {
window.webkit.messageHandlers[ios.name].postMessage(ios.args || null);
if (success) success();
} else {
$mHelper.toast('获取ios事件对象失败');
if (fail) fail()
}
// document.location = 'buyCar://appointment?arg1=1号参数&arg2=2号参数'
} else if (isAndroid()) {
if (!android || !android.name) return $mHelper.toast('未添加相应的android方法');
if (window.rentalAndroid) { // rentalAndroid 安卓命名定义
const result = (android.args || android.args === 0) ? window.rentalAndroid[android.name](android.args): window.rentalAndroid[android.name]();
if (success) success(result);
} else {
$mHelper.toast('获取android事件对象失败');
if (fail) fail();
}
}
}
// 单独暴露
export platformHandler
2. 调用封装的方法
platformHandler({
android: {
name: 'mapNavigation', // 方法名
args: startString // 参数-- 需要安卓定义好格式,可能不能传递对象结构数据等
},
ios: {
name: 'mapNavigation',
args: startString
})
3. 扩展
全局挂载该封装文件的方法platformHandler
- 直接挂载
在 Vue 项目的入口文件(通常是 main.js 或 main.ts)中,将对应的方法挂载到 Vue 的原型上,使其成为全局可用的方法。
直接挂载:是指在 Vue 的原型(Vue.prototype
)上直接添加属性或方法,而不需要通过插件机制。
main.js
import { platformHandler } from '/untils/platformFn'
Vue.prototype.$platformHandler = platformHandler
- 插件注册(
Vue.use
)引入全局
封装的方法相当于插件,可以通过Vue.use(more)
将插件注册到Vue
实例中,使其在全局范围内可用。
插件:通常是一个对象,包含一个函数。函数方法会在 Vue.use 调用时执行。
① 定义一个插件
more.js
function isIOS() {
return platform === 'ios';
}
function isAndroid() {
return platform === 'android';
}
export defalut function(Vue){
Vue.prototype.$isIOS = isIOS();
Vue.prototype.$isAndroid = isAndroid();
Vue.prototype.$iosStatusHeight = 44; // px
Vue.prototype.$androidStatusHeight = 20; // px
}
② 注册插件
在 Vue 项目的入口文件(如 main.js)中使用 Vue.use 注册插件。
main.js
import more from '/untils/more'
Vue.use(more)
- 引用该方法
this.$platformHandler({
android: {
name: 'mapNavigation', // 方法名
args: startString // 参数-- 需要安卓定义好格式,可能不能传递对象结构数据等
},
ios: {
name: 'mapNavigation',
args: startString
})
this.$isIOS
this.$iosStatusHeight