打通 App 与 H5
最后更新于:2018-10-26 10:04:46
1. 方案一:完全打通(新版方式)建议使用
H5 使用 JavaScript SDK ,采集到数据后,发往 App,App SDK 收到 JavaScript SDK 发送的数据后,首先会纠正事件中的 distinct_id,然后会把默认采集的属性加上,最后如果 App 端设置了公共属性,也会把公共属性加上。
Android SDK:需要使用 v1.7.10 及之后的版本
iOS SDK:需要使用 v1.7.14 及之后的版本
JavaScript SDK:需使用 v1.7.20及之后的版本
1.1 Android SDK 使用方法
在初始化 WebView 时,调用showUpWebView
:
SensorsDataAPI.sharedInstance().showUpWebView(WebView webView, boolean isSupportJellyBean, boolean enableVerify);
isSupportJellyBean :是否支持API level 16及以下的版本。 因为API level 16及以下的版本, addJavascriptInterface 有安全漏洞,请谨慎使用。
enableVerify :是否开启数据安全验证,true 表示验证。
注意:使用 Android SDK v1.10.3 及之后的版本,开启了数据安全验证后,会验证 App 端的数据接收地址与 H5 端的数据接收地址是否一致,如果不一致 H5 端的数据将不能发往 App 端,H5 端的数据直接上报;如果一致 H5 端的数据发往 App 端统一标识用户。
如果 App 内有第三方的 H5 页面,请将 enableVerify 指定为 true
如果使用的是腾讯的 X5 WebView ,调用showUpX5WebView
:
SensorsDataAPI.sharedInstance().showUpX5WebView(Object x5WebView, boolean enableVerify);
1.2 iOS SDK 使用方法
为了防止 H5 不在 App 环境下浏览时,track 的事件无法通过 JavaScript SDK 发送。在初始化完 iOS SDK 之后,调用如下接口:
[[SensorsAnalyticsSDK sharedInstance] addWebViewUserAgentSensorsDataFlag];
然后 WebView 即将加载新的请求时,调用[[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:request enableVerify:YES];
方法:
- 如果是 UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:request enableVerify:YES]) {
return NO;
}
// 在这里添加您的逻辑代码
return YES;
}
- 如果是 WKWebView
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:navigationAction.request enableVerify:YES]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
// 在这里添加您的逻辑代码
decisionHandler(WKNavigationActionPolicyAllow);
}
enableVerify :是否开启数据安全验证,YES 表示验证。
注意:使用 iOS SDK v1.10.3 及之后的版本,开启了数据安全验证后,会验证 App 端的数据接收地址与 H5 端的数据接收地址是否一致,如果不一致 H5 端的数据将不能发往 App 端,H5 端的数据直接上报;如果一致 H5 端的数据发往 App 端统一标识用户。
如果 App 内有第三方的 H5 页面,请将 enableVerify 指定为 YES
1.3 JavaScript SDK 使用方法
在参数配置中加入 use_app_track: true
, 这时候使用 JavaScript SDK 不会直接发送数据,都会发往 App 内,通过 App 内的 SDK 发送数据。
异步载入 在参数配置中加入 use_app_track: true
示例:
<script>
(function(para) {
var p = para.sdk_url, n = para.name, w = window, d = document, s = 'script',x = null,y = null;
w['sensorsDataAnalytic201505'] = n;
w[n] = w[n] || function(a) {return function() {(w[n]._q = w[n]._q || []).push([a, arguments]);}};
var ifs = ['track','quick','register','registerPage','registerOnce','clearAllRegister','trackSignup', 'trackAbtest', 'setProfile','setOnceProfile','appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify','login','logout','trackLink','clearAllRegister'];
for (var i = 0; i < ifs.length; i++) {
w[n][ifs[i]] = w[n].call(null, ifs[i]);
}
if (!w[n]._t) {
x = d.createElement(s), y = d.getElementsByTagName(s)[0];
x.async = 1;
x.src = p;
y.parentNode.insertBefore(x, y);
w[n].para = para;
}
})({
sdk_url: '在 github 下载新版本的 sensorsdata.min.js ',
name: 'sa',
//配置打通 App 与 H5 的参数
use_app_track: true,
server_url:'数据接收地址'
});
sa.quick('autoTrack'); //神策系统必须是1.4最新版及以上
</script>
在这种情况下,首先会判断外层是否有 App 的 SDK ,如果有的话,会往 App 的 SDK 发数据。如果没有,就正常发送数据。
注意:js 端开启安全验证需使用 1.10.1 及以后的版本。
2. 方案二:共享 distinct_id 达到打通(老版方式)
在混合模式开发的 App 中,H5 会先获取外部 App 的 distinct_id 等信息,这样 H5 就会使用 App 的 distinct_id ,达到用户打通的目的。此方案 H5 页面采集的数据并不会发往 App 端,而是通过 JavaScript SDK 直接上报。
2.1 Android SDK
在初始化 WebView 时,调用showUpWebView()
:
SensorsDataAPI.sharedInstance().showUpWebView(WebView webView, boolean isSupportJellyBean);
如果需要传递其它自定义属性,可以按如下方式调用:
try {
JSONObject properties = new JSONObject();
properties.put("testKey", "testValue");
SensorsDataAPI.sharedInstance().showUpWebView(webView, isSupportJellyBean, properties);
} catch (Exception ex) {
ex.printStackTrace();
}
isSupportJellyBean: 是否支持API level 16及以下的版本。 因为API level 16及以下的版本, addJavascriptInterface有安全漏洞,请谨慎使用。
注意:v1.6.7 及之后的版本才支持该功能。
2.2 iOS SDK
需要在 WebView 加载完成时,调用[[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:request];
方法:
- 如果是 UIWebView
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:request]) {
return NO;
}
// 在这里添加您的逻辑代码
return YES;
}
如果需要传递其它自定义属性,可以按如下方式调用:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
[properties setValue:@"testValue" forKey:@"testKey"];
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:webView WithRequest:request andProperties:properties]) {
return NO;
}
// 在这里添加您的逻辑代码
return YES;
}
- 如果是 WKWebView
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:_webView WithRequest:navigationAction.request]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
// 在这里添加您的逻辑代码
decisionHandler(WKNavigationActionPolicyAllow);
}
如果需要传递其它自定义属性,可以按如下方式调用:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
[properties setValue:@"testValue" forKey:@"testKey"];
if ([[SensorsAnalyticsSDK sharedInstance] showUpWebView:_webView WithRequest:navigationAction.request andProperties:properties]) {
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
// 在这里添加您的逻辑代码
decisionHandler(WKNavigationActionPolicyAllow);
}
注意:v1.6.14 及之后的版本才支持该功能。
2.3 JavaScript SDK
使用该功能需要使用 同步加载 JavaScript 代码的方式,即直接用 script 标签引入 SDK 代码 在代码生成工具中,选择高级设置,选择 SDK 引入方式为 同步模式。
JavaScript SDK 在 v1.6.6 之后的版本中提供一个方法 sa.getAppStatus 方法来获取 App 传递的信息,有两种使用方式。
sa.getAppStatus();
:同步返回 app_info 对象- 在 APP 打通的环境下会返回一个对象,内容如:
{type: 'iOS', distinct_id: '123456'}
。 - 在没有打通的环境,会返回 null。
- 这是一个即时运行的方法,可以连续被调用。
- 在 Android 环境下,刚开始直接调用这个方法,就能取到返回值,如果只有 Android 环境,推荐使用这个方法。
- 在 iOS 环境下,由于有调用延迟,不一定每次都能取到值。
- 在 APP 打通的环境下会返回一个对象,内容如:
sa.getAppStatus(function(app_info){ ... });
:异步回调- 在 APP 打通的环境下,会执行回调函数。
- 如果没有打通,回调函数不会被调用。
- 这个方法的主要作用,就是考虑到 iOS 的异步问题,所以会在取到数据后自动回调。
2.3.1 示例代码
- 使用回调方式,JavaScript SDK 获取到 AppInfo 之后再执行应用代码,例如:
sa.getAppStatus(function(app_info){
// 设置 ID
sa.identify(app_info.distinct_id);
// 跟踪事件
sa.track("ViewHomePage");
});
需要注意的是,这个回调在没有打通时不会触发。因此,如果这个页面既会在 App 打通的环境下使用,又会在未打通的情况下使用,需要参考以下代码来实现:
// 定义一个函数,这个函数根据当前是否在 App 内做出不同的处理
function trackInApp(trackFunc) {
// 这里需要判断是在 App 里还是在普通的浏览器里,例如可以根据 UserAgent 或者 Cookie 来判断
if (isInApp) {
sa.getAppStatus(function(app_info){
sa.identify(app_info.distinct_id);
trackFunc();
});
} else {
trackFunc();
}
}
// 实现实际的埋点逻辑
trackInApp(function() {
sa.quick('autoTrack');
sa.track("ViewHomePage");
})
// 上述只是针对代码埋点可以独立出来的情况下的处理方式。如果您的埋点代码必须在您的业务代码块中执行,需要考虑下面延迟的方式来处理
- 主动延迟调用。这种方式会导致数据延迟发送,在某些情况下可能会导致数据丢失,但是不用区分是否在 App 环境下:
setTimeout(function(){
var app_info = sa.getAppStatus();
// app_info 可能获取不到,例如非 App 环境,或者 App 端没有启用 AppInfo。
if (app_info) {
sa.identify(app_info.distinct_id);
}
sa.quick('autoTrack');
}, 500)
2.3.2 实现原理
- Android:
安卓提供 SensorsData_APP_JS_Bridge.sensorsdata_call_app 方法,JS 在载入后,会去调用 SensorsData_APP_JS_Bridge。
- iOS:
JS 提供 sensorsdata_app_js_bridge_call_js 函数,JS 在载入成功后,会通知 iOS 来调用这个方法。经测试,iOS 会在 JS 加载完成之后的 500ms 以内调用这个函数,因此存在调用延迟。