How to Decouple Hybrid H5 for True Cross‑Platform Compatibility
This article explains the concepts of Hybrid H5, its inherent coupling with native apps, and provides a step‑by‑step guide on decoupling through jsapi layers to restore cross‑platform functionality across multiple apps and platforms, illustrated with code examples and diagrams.
Cross‑platform capability is one of the most important features of H5, but Hybrid H5 often loses this ability because it heavily depends on a specific app. By decoupling the strong dependency, the cross‑platform nature of H5 can be restored. The author shares insights gained while developing the HandQQ Red Packet Reward project, which required multi‑app cross‑platform compatibility.
Hybrid H5 Cross‑Platform
Before diving in, two terms are defined:
Hybrid H5 mixes native capabilities with web pages, allowing calls to native APIs and thus tightly coupling with the host app. WeChat and HandQQ H5 pages are typical examples.
Cross‑platform means an H5 page can run on multiple platforms simultaneously; the more platforms supported, the stronger the cross‑platform capability.
Because Hybrid H5 relies on a specific app, it usually lacks cross‑platform support. This article explores how to restore it by decoupling the communication between Hybrid H5 and native.
Communication Principles Between Hybrid H5 and Native
Key points:
One communication medium: a custom native protocol.
Three communication actions: trigger, invoke, callback.
1. Communication medium – native protocol
The protocol resembles an HTTP‑like format:
protocol://path?param1=XXX¶m2=XXX¶m3=XXX#callbackComponents:
protocol: app‑defined scheme (e.g., jsbridge://).
path: native capability identifier.
parameters and callback identifier.
Example: jsbridge://method?a=2&b=3#h5MethodTag 2. Trigger
H5 actions that native can capture, such as location.href='jsbridge://method?a=2&b=3#h5MethodTag', cause the native side to receive the protocol string.
3. Invoke
Native parses the protocol and routes to the corresponding method. Example for iOS (Swift):
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
let url = request.URL
let scheme = url?.scheme
let method = url?.host
let query = url?.query
if scheme == "jsbridge" {
switch method! {
case "method": self.method()
case "openTenpayView": self.openTenpayView()
default: break
}
return false
}
return true
}4. Callback
After native finishes processing, it calls back the H5 JavaScript function:
webview.stringByEvaluatingJavaScriptFromString("H5MethodTag(data)")First Decoupling: In‑App Cross‑Platform via jsapi
Directly using the native protocol couples H5 to the current platform. To achieve in‑app cross‑platform support, apps expose a jsapi that abstracts protocol differences. The jsapi provides a unified function interface for H5.
Example jsapi definition:
ns.method({/* cfg */}, function(data) {/* callback */})Core steps of the jsapi:
API creation – encapsulate platform differences.
Protocol URL assembly – build the pseudo‑protocol string.
Iframe creation – send the request without affecting the H5 flow.
API creation example (HandQQ):
mqq.build('mqq.tenpay.openTenpayView', {
iOS: function(options, callback) {
var callbackName = callback ? mqq.callback(callback) : null;
mqq.invokeClient('pay', 'openTenpayView', {'params': options, 'callback': callbackName});
},
android: function(params, callback) {
mqq.invokeClient('pay', 'openTenpayView', JSON.stringify(params), callback);
},
supportInvoke: true,
support: {iOS: '4.6.1', android: '4.6.1'}
});Calling the API from H5:
mqq.tenpay.openTenpayView({/* data */}, function(ret) {/* callback */});Protocol URL assembly (simplified):
sn = storeCallback(callback);
url = 'jsbridge://' + encodeURIComponent(ns) + '/' + encodeURIComponent(method);
argus.forEach(function(a, i) {
if (exports.isObject(a)) a = JSON.stringify(a);
url += (i === 0 ? '?p=' : '&p' + i + '=') + encodeURIComponent(String(a));
});
url += '#' + sn;
result = openURL(url, ns, method);Iframe request:
var iframe = document.createElement('iframe');
iframe.style.cssText = 'display:none;width:0;height:0';
iframe.onload = failCallback;
iframe.src = url;
(document.body || document.documentElement).appendChild(iframe);
setTimeout(function(){ iframe && iframe.parentNode && iframe.parentNode.removeChild(iframe); }, 0);Second Decoupling: Cross‑App via H5‑Level jsapi
When a Hybrid H5 must run on multiple apps (e.g., both HandQQ and Qzone), a second layer of jsapi is introduced on the H5 side to abstract differences between app‑level jsapis.
Core actions of the H5 jsapi:
App‑jsapi difference request – load the appropriate app jsapi based on the runtime environment.
App‑jsapi difference encapsulation – provide a unified interface that maps to the underlying app’s native calls.
Environment detection and app‑jsapi loading example:
(function(){
var ua = navigator.userAgent || "",
isQQ = ua.match(/QQ\/([\d\.]+)/),
isQzone = ua.match("Qzone");
if (isQQ) {
document.write("<script src='https://open.mobile.qq.com/sdk/qqapi.js?_bid=152'><\/script>");
} else if (isQzone) {
document.write("<script src='https://qzonestyle.gtimg.cn/qzone/phone/m/v4/widget/mobile/jsbridge.js'><\/script>");
} else {
var currentHref = window.location.href;
window.location.href = 'mqqapi://forward/url?url_prefix=' + btoa(currentHref) + '&version=1&src_type=web';
setTimeout(function(){
if (confirm('请在手机QQ中使用~')) {
window.location.href = 'mqqapi://forward/url?url_prefix=' + btoa(currentHref) + '&version=1&src_type=web';
}
}, 0);
}
})();Encapsulation example for opening a native Tenpay view:
var mod = {
openTenpayView: function(param, callback) {
if (isQQ) {
var param = $.extend({userId: $.getCookie('uin').replace(/^o0*/, '')}, param);
mqq.tenpay.openTenpayView(param, callback);
} else {
var targetHref = 'http://testhost.com/jump.html?go=' + param.viewTag + '&_wv=' + (1+2+1024+2097152+33554432);
window.location.href = 'mqqapi://forward/url?url_prefix=' + btoa(targetHref) + '&version=1&src_type=web';
}
},
openUrl: function(paramObj) {
if (isQQ) {
mqq.ui.openUrl({url: paramObj.url, target: 1});
} else if (isQzone) {
mqq.invoke("ui", "openUrl", {url: paramObj.url, target: 1, style: 1});
} else {
location.href = paramObj.url;
}
}
};Conclusion
H5 is inherently cross‑platform, but Hybrid H5 loses this advantage due to tight coupling with native code. Restoring cross‑platform capability requires decoupling the native dependencies through layered jsapi abstractions, both within a single app and across multiple apps.
Decoupling is a crucial skill for developers; applying it to Hybrid H5 demonstrates how to regain lost capabilities and can lead to surprising benefits in other scenarios as well.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent TDS Service
TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
