業(yè)務(wù)需求
:藍(lán)牙外設(shè)<-->連接APP<-->打開WKWebView加載的Web小游戲目锭。
業(yè)務(wù)描述
:希望藍(lán)牙設(shè)備
設(shè)備通過連接APP
和Web網(wǎng)頁
進(jìn)行數(shù)據(jù)交互济蝉。Web中的游戲業(yè)務(wù)邏輯依賴藍(lán)牙設(shè)備
傳輸?shù)臄?shù)據(jù)魏割,同時(shí)Web中由藍(lán)牙設(shè)備
傳輸?shù)臄?shù)據(jù)觸發(fā)的某些業(yè)務(wù)狀態(tài)
笆檀,回傳給藍(lán)牙設(shè)備刻伊。
所以喘漏,這里暫時(shí)先記錄下App和Web通信部分的邏輯做葵;藍(lán)牙部分后期補(bǔ)上占哟。
iOS(Native)部分
1.1、 iOS WKWebView的初始化部分
/// js 調(diào)用 原生 無參酿矢、無返回值的函數(shù)
private let jsCallNativeMethodName = "jsCallNativeMethod"
/// js 調(diào)用 原生 無參榨乎、有返回值的函數(shù)
private let jsCallNativeJsonStringMethodName = "jsCallNativeJsonStringMethod"
/// js 調(diào)用 原生 有參、無返回值或有返回值的函數(shù)
private let jsCallNativeJsonStringWithParamName = "jsCallNativeJsonStringWithParam"
/// 原生 調(diào)用 js 有參瘫筐、無返回值或有返回值的函數(shù)
private let nativeCallScriptName = "nativeCallScript"
var webView: WKWebView!
var requestUrl:URL?
/// 初始化WebView
func initWebView() {
// 添加js對(duì)Native方法調(diào)用的監(jiān)聽
let jsCalliOSMethons = [jsCallNativeMethodName,
jsCallNativeJsonStringMethodName,
jsCallNativeJsonStringWithParamName,
nativeCallScriptName]
// native與JavaScript的交互管理
let config = WKWebViewConfiguration()
jsCalliOSMethons.forEach { name in
config.userContentController.add(self, name: name)
}
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width,
height: UIScreen.main.bounds.size.height), configuration: config)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
webView.scrollView.contentInsetAdjustmentBehavior = .never
webView.scrollView.contentInset = .zero
webView.scrollView.insetsLayoutMarginsFromSafeArea = false
view.addSubview(webView)
if (requestUrl != nil) {
webView.load(URLRequest(url: requestUrl!))
} else {
let url:String = "http://192.168.1.4:7456/web-mobile/web-mobile/index.html"
requestUrl = NSURL(string: url)! as URL
webView.load(URLRequest(url: requestUrl!))
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// 移除注冊(cè)的js方法
webView.configuration.userContentController.removeAllScriptMessageHandlers()
}
1.2谬哀、WKWebView的代理
WKScriptMessageHandler, WKNavigationDelegate, WKUIDelegate
//postMessage(message: any, targetOrigin: string, transfer?: Transferable[]): void;
//postMessage(message: any, options?: WindowPostMessageOptions): void;
func userContentController(_ userContentController: WKUserContentController, didReceive messa
WKScriptMessage) {
// 通過接收J(rèn)S傳出消息的name,進(jìn)行捕捉的回調(diào)方法
print("-- ??native 收到 js 調(diào)用:\(message.name) body:\(message.body)")
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("-- ??native did finish web load --")
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error)
print("-- ??native did fail \(error.localizedDescription) --")
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!,
withError error: Error) {
print("-- ??native did fail provisional navigation \(error.localizedDescription) --")
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
// 攔截到請(qǐng)求url
print("-- ??native decide policy for \(String(describing: navigationAction.request.url))
")
if navigationAction.request.url?.scheme?.caseInsensitiveCompare("jsCall") == .orderedSame
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
//alert(message?: any): void;
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
print("-- ??native alert message:\(message)")
let alertViewController = UIAlertController(title: "JS Alert Msg", message: message,
preferredStyle: .alert)
let sureAction = UIAlertAction(title: "Sure", style: .default) { action in
completionHandler()
}
alertViewController.addAction(sureAction)
self.present(alertViewController, animated: true)
}
// confirm(message?: string): boolean;
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String,
initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
print("-- ??native alert message:\(message)")
let alertViewController = UIAlertController(title: "JS Confirm Msg", message: message,
preferredStyle: .alert)
let sureAction = UIAlertAction(title: "Sure", style: .default) { action in
completionHandler(true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { action in
completionHandler(false)
}
alertViewController.addAction(sureAction)
alertViewController.addAction(cancelAction)
self.present(alertViewController, animated: true)
}
// prompt(message?: string, _default?: string): string | null;
func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String,
defaultText: String?, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping
(String?) -> Void) {
print("-- ??native run JS Text Input With Prompt:\(prompt)")
// let alertViewController = UIAlertController(title: "Text Input With Prompt", message: prompt, preferredStyle: .alert)
//
// alertViewController.addTextField { textField in
// textField.text = defaultText
// }
//
// let sureAction = UIAlertAction(title: "Sure", style: .default) { action in
// completionHandler(alertViewController.textFields?[0].text)
// }
// alertViewController.addAction(sureAction)
// self.present(alertViewController, animated: true)
switch prompt {
case jsCallNativeMethodName:// 無參、無返回值
self.jsCallNativeMethod()
completionHandler("")
return
case jsCallNativeJsonStringMethodName:// 無參严肪、有返回值
completionHandler(self.jsCallNativeJsonStringMethod())
return
case jsCallNativeJsonStringWithParamName:
completionHandler(self.jsCallNativeJsonStringWithParam(param: defaultText ?? ""))
return
default:
// 不處理無效的prompt
completionHandler("error param")
return
}
}
1.3、Native和JS的通信方法
extension GGWebViewController {
//MARK: - 被js調(diào)用的iOS方法
/// js 調(diào)用 原生 無參谦屑、無返回值的函數(shù)
func jsCallNativeMethod() {
print("-- ?? 這里是 原生 無參驳糯、無返回值的函數(shù) --")
var paramToScript:String = "iOS 調(diào)用 js 方法傳遞的參數(shù)"
self.dispatchEventToScript(param: paramToScript)
}
/// js 調(diào)用 原生 無參、有返回值的函數(shù)
func jsCallNativeJsonStringMethod() -> String {
let jsonString = "?? 這是 原生 無參氢橙、有返回值函數(shù) 返回給JS的值"
return jsonString
}
/// 調(diào)用 原生 有參酝枢、無返回值或有返回值的函數(shù)
/// 可通過param來判斷是否需要返回值
func jsCallNativeJsonStringWithParam(param:String) -> String {
guard let funcJsonData = param.data(using: .utf8) else{
print("--- ??解析出錯(cuò)1 ---")
return "param error"
}
do {
guard let funcInfoDic = try JSONSerialization.jsonObject(with: funcJsonData) as? Dictionary<String, Any> else{
print("---??解析出錯(cuò)3 --")
return "json serialization error"
}
print("---??web回調(diào)需要返回值的函數(shù):\(funcInfoDic)")
let jsonString = "?? Native接受JS參數(shù),并回調(diào)給JS"
return jsonString
} catch let errore {
print("--- ??解析出錯(cuò)2 ---:\(errore.localizedDescription)")
return errore.localizedDescription
}
}
//MARK: - iOS調(diào)用js的方法
func dispatchEventToScript(param: String) {
var callBack:String = nativeCallScriptName + "(\"\(param)\")"
webView.evaluateJavaScript(callBack) { response, error in
if (error != nil) {
print("-- ??\(self.nativeCallScriptName) error:\(String(describing: error))")
} else {
print("-- ??Native調(diào)用JS回調(diào)的參數(shù):\(String(describing: response))")
}
}
}
}
Web部分(TypeScript)
2.1悍手、Web訪問Native的方法(訪問的方法要在Native實(shí)現(xiàn)并注冊(cè))
// -- JS 主動(dòng)調(diào)用 原生 方法的處理 (對(duì)象方法) --
// 調(diào)用 原生 無參帘睦、無返回值的函數(shù)
public requestMethod() {
console.log("-- requestMethod --");
window.prompt("jsCallNativeMethod");
}
// 調(diào)用 原生 無參袍患、有返回值的函數(shù)
public requestMethodForValue() {
let jsonString = window.prompt("jsCallNativeJsonStringMethod");
console.log("-- requestMethodForValue" + jsonString + "--");
}
// 調(diào)用 原生 有參、無返回值的函數(shù)
public requestMethodWithParam() {
console.log("-- requestMethodWithParam --");
window.prompt("jsCallNativeJsonStringWithParam","這條message是傳遞給Native的參數(shù)");
}
// 調(diào)用 原生 有參竣付、有返回值的函數(shù)
public requestMethodWithParamForValue() {
let jsonString = window.prompt("jsCallNativeJsonStringWithParam","{\"desc\":\"這條message是傳遞給Native的JSON字符串參數(shù)诡延,同時(shí)該函數(shù)可接受Native返回給js的值\"}");
console.log("-- requestMethodWithParamForValue" + jsonString + "--");
}
2.3、Native訪問Web的方法
/ -- 原生 主動(dòng)調(diào)用 JS 方法的處理 (??原生調(diào)用JS的方法一定要掛載到全局window下古胆,否則Native會(huì)調(diào)用JS方法失斔亮肌)--
// param:參數(shù) 可為空
// string:返回值 可為空
function nativeCallScript(param:string):string {
console.log("-- nativeCallScript --");
console.log(param);
// 原生驅(qū)動(dòng)游戲角色運(yùn)動(dòng)
if (param != null) {
}
let jsonstring = "這條Message是 Native 主動(dòng)調(diào)用 JS 方法,將Native傳遞過來的param處理后逸绎,回調(diào)給Native"+ "->param:(" + param + ")";
return jsonstring;
}
(<any>window).nativeCallScript = nativeCallScript;