混合應用(hybird app)
在幾年前便進入大眾視野,近來更是越發風生水起,深受人民群眾的喜愛。
概念
什麼是混合應用
混合應用(hybird app)
顧名思義,便是將web app與native app混合在一起,既享受html快速開發、快速版本迭代帶來的便利,也能使用原生app呼叫系統介面和第三方SDK的強大擴充套件能力。
混合方式
如同茴字有幾種寫法
一般,構建混合應用也有不同的方式。其中一種是主要使用靜態html,用 phonegap
或 cordova
加殼的方式打包成app。另一種則是小部分webview直接引入服務端渲染的html,其他功能都是原生app開發。
其中前一種方式最為出名的解決方案便是使用 angular.js
+ cordova
的 ionic,而使用後一種方式的app則數不勝數。
但是無論使用哪一種方式,都面臨一個問題,html和app的互動。html自己不會動起來,本文將淺談javascript如何互動app和html。
互動
方法注入
常見的app和html互動有 使用url
和 互相呼叫方法
兩種方式。使用url
這種方式比較簡單,透過 location.href = 'url'
,即可將方法和引數傳遞給app,但是無法傳遞複雜的資料。互相呼叫方法
這種方式則較為複雜,除了需要app端寫好呼叫的方法注入到 window
物件之外,還需要JavaScript暴露方法給app使用。以常見的評論互動為例:
// 點選“發表評論”,js需要呼叫app的評論框
$('.js-comment').click(function(){
window.appMethod.comment();
});
// app端在使用者點選“傳送”按鈕時,再呼叫javascript的插入評論方法(我不會app開發,以下是虛擬碼)
function comment(){
TEXTAREA.OPEN();
}
SUBMIT_BUTTON.CLICK(function(){
NSString * result = [self.webView stringByEvaluatingJavaScriptFromString:@"window.jsMethod.comment()"];
})
其中 window.appMethod
這個方法,是一個從 iOS 和 android 方法中提取而來的方法,根據手機系統不同,使用不同策略,例如:
var window.appMethod = null;
var androidMethod = {
comment: function(){
window.android.comment();
}
};
var iOSMethod = {
comment: function(){
location.href = 'ios://comment?'
}
};
window.appMethod = iOS_DEVICE ? iOSMethod : androidMethod;
相比方法的注入點,策略處理,方法的呼叫時機更為重要。在js中呼叫一個不存在方法,會發生錯誤從而導致程式碼無法繼續向下執行。
比如進入頁面時,app需要告訴html一些登入資訊,以初始化點贊,收藏等元件。如果由app直接呼叫js方法去通知,那麼很可能頁面還沒載入完,而發生上面提到的錯誤。
所以好的時機是讓js主動去向app發起請求,示例:
// 不和諧:app直接通知js更新使用者登入狀態,可能會發生錯誤
eval('window.jsMethod.setUser();')
// 和諧:js主動去向app發起請求
$(function(){
window.appMethod.getUser();
})
// app端在接收到getUser方法後,呼叫js方法(我不會app開發,以下是虛擬碼)
function getUser(){
// 獲取user狀態,然後執行
NSString * result = [self.webView stringByEvaluatingJavaScriptFromString:@"window.jsMethod.setUser()"];
}
引數傳遞
以上的示例中的方法並沒有進行引數傳遞,是為了留到這裡。
相比JavaScript,在android和iOS方法中傳遞引數顯得極為嚴格,除了要指定引數個數,還要指定引數型別。
雖然可以透過陣列的方式進行不定個數引數的傳遞,但是指定引數型別還是挺煩人的。所以建議始終使用 String
型別作為引數進行傳遞,複雜的json格式引數使用 JSON.stringify
。使用url傳遞則需要對引數進行 encode 編碼。
以上面的發表評論為例:
# 本段程式碼使用了jquery
// js給app傳參
var androidMethod = {
comment: function(params){
window.android.comment( JSON.stringify(params) );
}
};
var iOSMethod = {
comment: function(params){
location.href = 'ios://comment?'+$.param(params)
}
};
... ...
$('.js-comment').click(function(){
var params = {
"user_id": 30,
"article_id": 958,
"article_type": "news"
};
window.appMethod.comment(params);
});
// app給js傳參
SUBMIT_BUTTON.CLICK(function(){
var params = {
"comment_id": 5484,
"comment_content": "我不會寫app,姑且用js寫虛擬碼"
};
NSString * result = [self.webView stringByEvaluatingJavaScriptFromString:@"window.jsMethod.comment( JSON.stringify(params) )"];
})
方法監聽
這裡的方法監聽指的是app對js方法的單向監聽。
因為需要app監聽的js方法,都是顯示的呼叫了app方法,或是跳轉到了一個url。呼叫app的方法自不待言,url的監聽卻有多種。
一種是a連結的 http
GET 請求的監聽,多見於 下一篇文章
, 相關文章
等跳轉頁面的方法。一般來說不用帶引數。還有一種是自定義的 schema
監聽,使用這種方式一般是不帶或帶較少的引數,比如 myiOS://mymethod?
。
資源載入
把資源載入放到互動裡面,我也不知道合不合適。對於 第一種混合方式 來說,可以把更多的靜態資源放到本地,然後透過app介面載入。對於第二種,更多的還是從服務端渲染並載入資源。
對於一些互動類的資料,而非資源,既可以選擇存放在瀏覽器的localStorge中,也可以選擇存放於app本地檔案,這取決於哪一方進行操作運算了。
除錯
html的移動端除錯時很困難的,嵌入app的html除錯更是難上加難。因為js和app的方法相互呼叫,任何一方出錯,都會導致程式不按套路執行。
除了仔細的約定兩端的方法和檢查程式碼的錯誤外,還需要一個強力的工具。在這裡推薦使用 vConsole ,可以比較直觀的定位到錯誤。
vConsole 截圖
其他
相容性
html在app中的相容性取決於app內嵌瀏覽器核心。iOS系統預設的瀏覽器是safari,而andriod系統預設的瀏覽器則五花八門。
如果選擇系統預設瀏覽器作為內嵌瀏覽器的話,ios一般相容性較好,能取得和PC端一致的效果。android機型則會比較悲劇,使用 crosswalk方案 或許是個正確的選擇。
特性啟用
在內嵌瀏覽器中,html5的某些特性預設是關閉的,比如 localStorge
, 需要app端手動去開啟。所以在開發中一定要做好可用性檢測,減少出現bug的機率。
區域性檢視
當html作為webview的區域性檢視被載入時,由於app雖然可以獲取到頁面載入後的高度,但是無法獲取動態改變後的高度,使得區域性滾動失效。
所以在作為區域性檢視載入時,如果需要頁面高度會根據比如評論,動畫效果而發生改變的話,需要及時通知app更新webview高度。