本文介绍小程序数据上报插件及自定义方法
一、插件框架及QuickTracking上报插件整体介绍

1. 前端部分说明
小程序集成 "MiniApp PageEvent Report JS-library" 获取 "小程序页面生命周期事件" 并通过jsapi发送给LifeCycleService。
注意:此功能仅支持WindVane
1.1 如何集成
如下,在小程序的html文件中引入通过script标签引入https://g.alicdn.com/code/npm/@alife/windvane-page-lifecycle-hooks/0.1.0/index.js,
注意该js的引入顺序,必须在引入windvane.js后。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, maximum-scale=1.0,viewport-fit=cover" />
<title>EMAS-WindVane JSBridge Demo</title>
<link rel="stylesheet" href="static/css/main.css" />
</head>
<body>
<div id="app"></div>
<!-- <script src="//g.alicdn.com/code/lib/react/18.2.0/umd/react.development.js"></script> -->
<!-- <script src="//g.alicdn.com/code/lib/react-dom/18.2.0/umd/react-dom.development.js"></script> -->
<!-- <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script> -->
<script src="https://g.alicdn.com/mtb/lib-windvane/3.0.0/windvane.js"></script>
<script src="https://g.alicdn.com/code/npm/@alife/windvane-page-lifecycle-hooks/0.1.0/index.js"></script>
<script src="static/js/bundle.js"></script>
</body>
</html>
1.2 同步小程序生命周期
小程序的生命周期如下:
onPageStart: 小程序初始化完成时触发,全局只触发一次
onPageShow: 小程序打开页面或从后台进入前台显示时触发
onPageHide:小程序离开页面或从前台到后台时触发
onPageEnd:小程序关闭
小程序上报的页面参数如下:
url:当前页面url,如 https://g.alicdn.com/superapp-fe-templates/JSAPITest/1.0.1/index.html#/
fullUrl:当前页面url,如 https://g.alicdn.com/superapp-fe-templates/JSAPITest/1.0.1/index.html?spm=defwork.home.0.0.3f085c4bPdhs2c#/
title:当前页面标题
userAgent: 当前设备的navigator.userAgent, 如"Mozilla/5.0 (Linux; Android 11; IN2010 Build/RP1A.201005.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/132.0.6834.163 Mobile Safari/537.36 TTID/600000@DemoApp_Android_1.0.0 WindVane/8.5.0"
viewportHeight: 当前视窗高度,如744
viewportWidth: 当前视窗宽度,如384
referrer: 当前请求页面的来源页面的地址,如 https://1511899753493821546496.app.mini.windvane.suite.emas.alibaba.com/
user_id:当前用户userId,在容器初始化注册的EMASUserInfoService(iOS),IUserInfoService(Android )中的userId参数
mini_app_id:当前打开的小程序的appId
mini_app_version: 当前打开的小程序版本号
mini_app_type: 当前打开的小程序类型,如windvane 或者 uniapp
app_code: 应用id, 容器初始化传入的appCode
timestamp:页面触发当前时间戳
1.2.1 打开小程序
如图会调用JSAPI, WVMiniPageEvent上报onPageStart、onPageShow,并上报如图的页面参数

1.2.2 页面跳转
如图会调用JSAPI, WVMiniPageEvent上报onPageHide当前页面,onPageShow目标页面,并上报如图的页面参数

1.2.3 前台切后台
如图会调用JSAPI, WVMiniPageEvent上报onPageHide当前页面,并上报如图的页面参数

1.2.4 后台切前台
如图会调用JSAPI, WVMiniPageEvent上报onPageShow当前页面,并上报如图的页面参数

1.2.5 关闭小程序
如图会调用JSAPI, WVMiniPageEvent上报onPageHide、onPageEnd,并上报如图的页面参数

2. 客户端说明
2.1 MiniApp Event: 监听小程序生命周期事件 包括
MiniApp Life Cycle Event | Android Activity | iOS ViewController |
start | onCreate | viewDidLoad |
show | onResume | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; |
hide | onPause | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; |
close | onDestory | viewWillDisappear (if (self.isMovingFromParentViewController|| self.navigationController.isBeingDismissed)) |
2.2 MiniAppPageEvent(仅支持WindVane): 监听小程序页面生命周期事件
2.3 PluginService:插件框架用于插件管理
用于注册插件
用于获取指定插件
2.4 LifeCycleService:
用于接收 MiniApp PageEvent Report JS-library 通过jsapi(MiniAppPageEvent jsapi)发送过来的小程序页面生命周期事件MiniApp PageEvent Report JS-library
用于监听 小程序周期(MiniApp Event)事件
将 小程序页面生命周期事件 & 小程序生命周期事件 通过观察者对象(Observer/Callback)发送给上报插件
目前LifeCycleService 监听的生命周期事件如下
事件类型/Event Type | 小程序页面事件 Mini App Page Event | 小程序事件 Mini App Event |
打开start | YES | YES |
显示show | YES | YES |
隐藏hide | YES | YES |
关闭end/close | YES (only for Android) | YES |
二、自定义插件开发 Custom Plugin Development
1. 导入依赖包.
implementation com.aliyun.emas.suite.foundation:mini-app-plugin-base:1.0.0pod 'MiniAppPluginBase'2. 插件开发.
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.plugin.BasePlugin;
public class CustomPlugin extends BasePlugin {
public CustomPlugin(Context context, ...) {
super(context);
...
}
@Override
public void start() {
...
}
...
}#import <EMASMiniAppService/EMASBasePlugin.h>
@interface EMASCustomPlugin : EMASBasePlugin
@property(nonatomic, strong) EMASPluginContext *plugContext;
@implementation EMASCustomPlugin
- (void)setPluginContext:(EMASPluginContext *)pluginContext {
self.plugContext = pluginContext;
}
- (void)start {
[super start];
//需要注册观察者对象 register Observer Object
}
import UIKit
import EMASMiniAppService
@objc class EMASCustomPlugin: EMASBasePlugin, EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver {
var plugContext:EMASPluginContext?
//Note: need to call the Swift setPluginContext method, remember to add @objc
@objc func setPluginContext(_ pluginContext: EMASPluginContext) {
self.plugContext = pluginContext
}
override func start() {
super.start()
///需要注册观察者对象 register Observer Object
}
}3. 插件注册.
CustomPlugin customPlugin = new CustomPlugin(context, ...);
miniAppService.registerPlugin("PluginName", customPlugin);//初始化容器时
EMASCustomPlugin *plugin = [[EMASCustomPlugin alloc] init];
[miniAppService registerPlugin:@"PluginName" plugin:plugin];///初始化容器时
let plugin = EMASCustomPlugin()
miniAppService.registerPlugin("PluginName", plugin: plugin)4. 插件获取.
import com.alibaba.module.android.mini.app.service.plugin.PluginService;
BasePlugin plugin = PluginService.getInstance().getPlugin("PluginName");EMASBasePlugin *plugin = [miniAppService getPlugin:@"PluginName"];let plugin = miniAppService.getPlugin("PluginName")5. 插件启动.
import com.alibaba.module.android.mini.app.service.plugin.PluginService;
// 方式1
CustomPlugin customPlugin = new CustomPlugin(context, ...);
customPlugin.start();
// 方式2
BasePlugin plugin = PluginService.getInstance().getPlugin("PluginName");
plugin.start();
// 方式1
EMASCustomPlugin *plugin = [[EMASCustomPlugin alloc] init];
[miniAppService registerPlugin:@"PluginName" plugin:plugin];
[plugin start];
// 方式2
EMASBasePlugin *plugin = [miniAppService getPlugin:@"PluginName"];
[plugin start];
// 方式1
let plugin = EMASCustomPlugin()
miniAppService.registerPlugin("PluginName", plugin: plugin)
plugin.start()
// 方式2
let plugin = miniAppService.getPlugin("PluginName")
plugin.start()6. 在插件中获取LifeCycleService.
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.environment.PluginEnv;
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.ILifeCycleService;
ILifeCycleService lifeCycleService = PluginEnv.getInstance().getContainerContext().getLifeCycleService()#import <EMASMiniAppService/EMASLifeCycleService.h>
#import <EMASMiniAppService/EMASIMiniAppEventObserver.h>
#import <EMASMiniAppService/EMASIMiniAppPageEventObserver.h>
@interface EMASCustomPlugin()<EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver>
@property(nonatomic, strong) EMASPluginContext *plugContext;
@end
@implementation EMASCustomPlugin
- (void)getlifeCycleService {
EMASLifeCycleService *lifeCycleService = self.plugContext.context.getLifeCycleService;
}@objc class EMASCustomPlugin: EMASBasePlugin, EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver {
var plugContext:EMASPluginContext?
func getlifeCycleService() {
let lifeCycleService = self.plugContext?.context.getLifeCycleService()
}
}三、自定义上报插件开发

1. 实现 小程序生命周期事件 和 小程序页面生命周期事件 观察者对象
小程序参数说明如下:
user_id:当前用户userId,在容器初始化注册的EMASUserInfoService(iOS),IUserInfoService(Android )中的userId参数
mini_app_id:当前打开的小程序的appId
mini_app_version: 当前打开的小程序版本号
mini_app_type: 当前打开的小程序类型,如windvane 或者 uniapp
app_code: 应用id, 容器初始化传入的appCode
timestamp:页面触发当前时间戳
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.observer.IMiniAppEventObserver;
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.observer.IMiniAppPageEventObserver;
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.plugin.BasePlugin;
public class CustomReportPlugin extends BasePlugin implements IMiniAppEventObserver, IMiniAppPageEventObserver {
// 实现 小程序生命周期事件 回调
@Override
void onMiniAppStart(Map<String, Object> params) {
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
@Override
void onMiniAppClose(Map<String, Object> params) {
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
@Override
void onMiniAppShow(Map<String, Object> params) {
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
@Override
void onMiniAppHide(Map<String, Object> params) {
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
// 实现 小程序页面生命周期事件 回调
void onPageStart(Map<String, Object> params) {
String url = (String) params.get("url");
String fullUrl = (String) params.get("fullUrl");
String title = (String) params.get("title");
String referrer = (String) params.get("referrer");
String userAgent = (String) params.get("userAgent");
double viewportWidth = (double) params.get("viewportWidth");
double viewportHeight = (double) params.get("viewportHeight");
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
void onPageHide(Map<String, Object> params) {
String url = (String) params.get("url");
String fullUrl = (String) params.get("fullUrl");
String title = (String) params.get("title");
String referrer = (String) params.get("referrer");
String userAgent = (String) params.get("userAgent");
double viewportWidth = (double) params.get("viewportWidth");
double viewportHeight = (double) params.get("viewportHeight");
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
void onPageShow(Map<String, Object> params) {
String url = (String) params.get("url");
String fullUrl = (String) params.get("fullUrl");
String title = (String) params.get("title");
String referrer = (String) params.get("referrer");
String userAgent = (String) params.get("userAgent");
double viewportWidth = (double) params.get("viewportWidth");
double viewportHeight = (double) params.get("viewportHeight");
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
void onPageEnd(Map<String, Object> params) {
String url = (String) params.get("url");
String fullUrl = (String) params.get("fullUrl");
String title = (String) params.get("title");
String referrer = (String) params.get("referrer");
String userAgent = (String) params.get("userAgent");
double viewportWidth = (double) params.get("viewportWidth");
double viewportHeight = (double) params.get("viewportHeight");
String userId = (String) params.get("user_id");
String appId = (String) params.get("mini_app_id");
String version = (String) params.get("mini_app_version");
String appType = (String) params.get("mini_app_type");
String appCode = (String) params.get("app_code");
String timestamp = (String) params.get("timestamp");
...
}
}@interface EMASCustomPlugin()<EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver>
@property(nonatomic, strong) EMASPluginContext *plugContext;
@end
@implementation EMASCustomPlugin
#pragma mark -EMASIMiniAppEventObserver
- (void)onMiniAppStart:(NSDictionary *)params {
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
-(void)onMiniAppShow:(NSDictionary *)params {
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
- (void)onMiniAppHide:(NSDictionary *)params {
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
- (void)onMiniAppClose:(NSDictionary *)params {
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
#pragma mark -EMASIMiniAppPageEventObserver
- (void)onPageStart:(NSDictionary *)params {
NSString *url = [params objectForKey:@"url"];
NSString *fullUrl = [params objectForKey:@"fullUrl"];
NSString *title = [params objectForKey:@"title"];
NSString *referrer = [params objectForKey:@"referrer"];
NSString *userAgent = [params objectForKey:@"userAgent"];
double viewportWidth = [params objectForKey:@"viewportWidth"];
double viewportHeight = [params objectForKey:@"viewportHeight"];
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
- (void)onPageShow:(NSDictionary *)params {
NSString *url = [params objectForKey:@"url"];
NSString *fullUrl = [params objectForKey:@"fullUrl"];
NSString *title = [params objectForKey:@"title"];
NSString *referrer = [params objectForKey:@"referrer"];
NSString *userAgent = [params objectForKey:@"userAgent"];
double viewportWidth = [params objectForKey:@"viewportWidth"];
double viewportHeight = [params objectForKey:@"viewportHeight"];
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
- (void)onPageHide:(NSDictionary *)params {
NSString *url = [params objectForKey:@"url"];
NSString *fullUrl = [params objectForKey:@"fullUrl"];
NSString *title = [params objectForKey:@"title"];
NSString *referrer = [params objectForKey:@"referrer"];
NSString *userAgent = [params objectForKey:@"userAgent"];
double viewportWidth = [params objectForKey:@"viewportWidth"];
double viewportHeight = [params objectForKey:@"viewportHeight"];
NSString *appId = [params objectForKey:@"mini_app_id"];
NSString *appType = [params objectForKey:@"mini_app_type"];
NSString *userId = [params objectForKey:@"user_id"];
NSString *version = [params objectForKey:@"mini_app_version"];
NSString *appCode = [params objectForKey:@"app_code"];
NSString *timestamp = [params objectForKey:@"timestamp"];
...
}
- (void)onPageEnd:(NSDictionary *)params {
// iOS端次方法不调用
}import UIKit
import EMASMiniAppService
@objc class EMASCustomPlugin: EMASBasePlugin, EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver {
var plugContext:EMASPluginContext?
///EMASIMiniAppEventObserver
func onMiniAppStart(_ params: [AnyHashable : Any]) {
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onMiniAppShow(_ params: [AnyHashable : Any]) {
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onMiniAppHide(_ params: [AnyHashable : Any]) {
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onMiniAppClose(_ params: [AnyHashable : Any]) {
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
///EMASIMiniAppPageEventObserver
func onPageStart(_ params: [AnyHashable : Any]) {
let url = params["url"] as? String
let fullUrl = params["fullUrl"] as? String
let title = params["title"] as? String
let referrer = params["referrer"] as? String
let userAgent = params["userAgent"] as? String
let viewportWidth = params["viewportWidth"] as? Double
let viewportHeight = params["viewportHeight"] as? Double
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onPageShow(_ params: [AnyHashable : Any]) {
let url = params["url"] as? String
let fullUrl = params["fullUrl"] as? String
let title = params["title"] as? String
let referrer = params["referrer"] as? String
let userAgent = params["userAgent"] as? String
let viewportWidth = params["viewportWidth"] as? Double
let viewportHeight = params["viewportHeight"] as? Double
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onPageHide(_ params: [AnyHashable : Any]) {
let url = params["url"] as? String
let fullUrl = params["fullUrl"] as? String
let title = params["title"] as? String
let referrer = params["referrer"] as? String
let userAgent = params["userAgent"] as? String
let viewportWidth = params["viewportWidth"] as? Double
let viewportHeight = params["viewportHeight"] as? Double
let appId = params["mini_app_id"] as? String
let appType = params["mini_app_type"] as? String
let userId = params["user_id"] as? String
let version = params["mini_app_version"] as? String
let appCode = params["app_code"] as? String
let timestamp = params["timestamp"] as? String
}
func onPageEnd(_ params: [AnyHashable : Any]) {
///iOS端次方法不调用
}
}2. 注册观察者对象
import com.alibaba.emas.android.windvane.mini.app.pluginsdk.environment.PluginEnv;
public class CustomReportPlugin extends BasePlugin implements IMiniAppEventObserver, IMiniAppPageEventObserver {
private void registerObserver() {
PluginEnv.getInstance().getContainerContext().getLifeCycleService().registerMiniAppObserver(this);
PluginEnv.getInstance().getContainerContext().getLifeCycleService().registerMiniPageObserver(this);
}
}
#import <EMASMiniAppService/EMASIMiniAppEventObserver.h>
#import <EMASMiniAppService/EMASIMiniAppPageEventObserver.h>
@interface EMASCustomPlugin()<EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver>
@property(nonatomic, strong) EMASPluginContext *plugContext;
@end
@implementation EMASCustomPlugin
- (void)registerObserver {
[self.plugContext.context.getLifeCycleService registerMiniAppObserver:self];
[self.plugContext.context.getLifeCycleService registerMiniPageObserver:self];
}import UIKit
import EMASMiniAppService
@objc class EMASCustomPlugin: EMASBasePlugin, EMASIMiniAppEventObserver, EMASIMiniAppPageEventObserver {
var plugContext:EMASPluginContext?
func registerObserver() {
self.plugContext?.context.getLifeCycleService().registerMiniAppObserver(self)
self.plugContext?.context.getLifeCycleService().registerMiniPageObserver(self)
}
}3. 注册、获取、启动插件
详见 2.3 ~ 2.5
4. 其余小程序事件
自定义jsapi
四、注意事项
打开小程序界面后onPageShow会调用两次
iOS 小程序关闭不会调用onPageEnd事件(需要在关闭小程序的方法中调用关闭页面的方法)