拖稿了好久的「Hybrid APP開發系列」又更新了~
今天繼續寫JSSDK
為什麼會有JSSDK
我之前文章介紹了通過 JSBridge 實現頁面和NA的相互呼叫,並且介紹了模板本地包的開發和後臺維護系統。今天介紹的是JSSDK,通過 JSSDK 可以實現:
抹平JSBridge的平臺實現差異
對齊端能力,內部消化版本差異
sdk封裝後的程式碼更加符合前端習慣
許可權控制、鑑權、對外開放,實現生態建設
關於sdk的程式碼級別的設計,可以參考文章:《JSSDK設計指南》
如果做過微信頁面開發的,應該都知道 wx.js
,這就是微信的JSSDK,在微信內需要呼叫微信的端能力就需要引入這個js。
JSSDK的設計
JSSDK的設計包括兩部分:
隨著每個NA客戶端版本內建的js,稱為:
inject.js
,他的主要作用是封裝JSBridge邏輯,通過隨版更新實現減少端能力的版本分裂,降低整個sdk的程式碼複雜性。inject.js
是一段js程式碼,當客戶端載入一個頁面的時候,由客戶端在適當的時機注入到webview內執行,執行後的程式碼就會有給webview增加js方法,例如微信的_WeixinJSBridge
,類比chrome開發外掛當中的content_scripts
,可以在document_start
、document_end
等時機進行執行。雲端JS,即實際暴漏給開發者使用的js,稱為:
jssdk.js
,這個是真正開發者使用的sdk檔案,通過script
外鏈引入,例如wx.js
,這個js檔案通過和inject.js
進行交換,完成端能力的呼叫、鑑權和客戶端事件監聽等操作
inject.js 和 jssdk.js工作機制
inject.js
是客戶端和 jssdk
的「翻譯官」,他接受頁面 jssdk
的方法呼叫,將呼叫的命令解析成客戶端可以理解的「語言」(JSBridge)然後傳給客戶端,同時當客戶端有事件/回撥響應的時候,也通過 inject.js
進行分發/回撥。
舉例:NA分享能力
例如,客戶端實現了一個分享皮膚的UI元件,開放給web頁面可以呼叫,這時候需要呼叫NA的端能力,JS需要將分享的:icon_url、title、content、link、type甚至訂製的NA皮膚資訊等傳給NA,NA開始彈出這個皮膚,使用者進入NA層進行互動;
當使用者分享成功、失敗、取消等事件發生的時候,需要回撥JS程式碼,使用者由回到了web頁面,NA回撥了JS callback,JS實現後續的邏輯。
jsbridge為:
demoapp://share/dialog?title=三水清&link=http://js8.in&
複製程式碼
icon_url=xxx&content=我發現一個很有用的前端公眾號複製程式碼
inject.js
程式碼封裝如下:
;(function (window, document) {複製程式碼
function invoke (module, action, args, callback) {複製程式碼
let scheme = `demoapp://${module}/${action}?`複製程式碼
if (isFunction(args)) {複製程式碼
callback = args複製程式碼
args = null複製程式碼
}複製程式碼
// 處理下引數複製程式碼
if (isString(args)) {複製程式碼
scheme += args複製程式碼
} else if (isObject(args)) {複製程式碼
each(args, (k, v) => {複製程式碼
if (isObject(v) || isArray(v)) {複製程式碼
v = JSON.stringify(v)複製程式碼
}複製程式碼
scheme += `${k}=${v}`複製程式碼
})複製程式碼
}複製程式碼
// callback獨立傳,方便全域性函式名命名複製程式碼
if (isFunction(callback)) {複製程式碼
var funcName = '_jsbridge_cb_' + getId()複製程式碼
window[funcName] = function () {複製程式碼
callback.apply(window, ([]).slice.call(arguments, 0))複製程式碼
}複製程式碼
scheme += (!~scheme.indexOf('?') ? '&' : '?') + `callback=${funcName}`複製程式碼
}複製程式碼
if (os.ios && versionCompare(os.version, '9.0') >= 0) {複製程式碼
window.location.href = scheme複製程式碼
} else {複製程式碼
var $node = document.createElement('iframe')複製程式碼
$node.style.display = 'none'複製程式碼
$node.src = scheme複製程式碼
var body = document.body || document.getElementsByTagName('body')[0]複製程式碼
body.appendChild($node)複製程式碼
setTimeout(function () {複製程式碼
body.removeChild($node)複製程式碼
$node = null複製程式碼
}, 10)複製程式碼
}複製程式碼
}複製程式碼
var $ = {複製程式碼
share: function (opts, callback) {複製程式碼
var defaultOpts = {複製程式碼
url: location.href,複製程式碼
title: '三水清',複製程式碼
content: '最好的前端公眾號',複製程式碼
icon_url: 'http://baidu.com/icon.png'複製程式碼
}複製程式碼
opts = Object.assign(defaultOpts, opts)複製程式碼
invoke('share', 'dialog', opts, callback)複製程式碼
}複製程式碼
}複製程式碼
window._InjectJS_ = $複製程式碼
}(window, document))複製程式碼
jssdk.in
程式碼示例:
window.jssdk = {複製程式碼
share: _InjectJS_.share複製程式碼
}複製程式碼
頁面呼叫:
jssdk.share({url: 'http://js8.in'}, (err, data) => {複製程式碼
if (!err) {複製程式碼
if (data.errno === 1) {複製程式碼
alert('失敗')複製程式碼
}else if (data.errno === 2) {複製程式碼
alert('取消')複製程式碼
}else {複製程式碼
alert(data.media) // 分享的平臺id,比如webxin_timeline複製程式碼
}複製程式碼
}複製程式碼
})複製程式碼
這樣 jssdk
呼叫 inject.js
寫法,看似多此一舉,實則很巧妙,試想一下下面的場景:
客戶端某個版本分享能力升級,需要做相容
某版本分享能力有bug,會引起crash,不能在此版本呼叫
分享成功之後的回撥需要做鑑權,防止惡意刷分享行為
JSBridge有scheme調起換成jsinterface的調起(參考本系列JSBridge文章)
如果這些程式碼都寫在 jssdk.js
,那麼隨著版本的積累,程式碼會越來越臃腫,並且所有版本的端能力都集中在 jssdk.js
,很不利於管理,歷史的包袱也甩不掉。
inject.js的注入時機
因為 inject.js
的設計機制,所以我們希望 inject.js
能夠越早注入越好,這樣我們在頁面head使用 jssdk.js
就不會找不到物件了!
我們知道安卓WebView中可以通過 webview.loadUrl("javascript:xxx”)
的方式來呼叫js裡面的程式碼,那麼,我們也可以利用 webview.loadUrl("javascript:xxx”);
的方式來載入注入一段 js 程式碼 。
安卓WebView 需要通過 webView.setWebViewClient(new MyWebClient());
的方式來監聽網頁載入的各個週期方法回撥,那麼我們只需要在 onPageFinished(WebView view, String url)
中注入提前設定好的js 即可
在iOS中也有對應的時間點: webViewDidFinishLoad
和 didCreateJavaScriptContext
我們能夠找到的注入時機有限,為了保證jssdk程式碼在呼叫的時候,已經注入成功 inject.js
,我們只能實現類似 DOMContentLoaded
這樣的 ready
方法回撥,使用jssdk的時候,全部寫在 jssdk.ready()
內(類似 $(document).ready
),當頁面 inject.js
注入成功則丟擲 ready
事件,然後積累的事件棧依次出棧執行。
總結
本文介紹了hybrid開發中為webview實現一個jssdk,介紹了 inject.js
的注入時機, inject.js
除了端能力的呼叫,還可以和客戶端實現授權(如:微信的接入授權需要申請appid和token),同時還可以針對所有的調起指令和回撥進行安全校驗,遮蔽非法的呼叫和回撥,本文只實現了最簡單的呼叫,這些高階的設計後面文章有機會再介紹,今天敲完收工搬家過節 :P
相關文章
@三水清
未經允許,請勿轉載。
掘金更新比公眾號晚一週左右。