神策(Android)- 集成基础埋点的整个过程

记得最早以前都是用友盟全家桶,埋点是用友盟,推送也是用友盟;但是近俩年我参与开发的app,埋点都是用神策、推送都是用极光私服,分享都是去对应集成对应平台的SDK

神策篇

一切以 官方文档 为准,因为随着版本升级,集成文档或许多多少少会有一些变动,此篇仅记录我集成神策基础埋点的整个过程

基础配置

基础配置:涵盖 AGP 和 Sdk 的引入

  • 关于如何在 AGP 8.0+ 版本中使用插件以及插件的常用配置,请参考 SDK 插件说明
  • Android Plugin 需要 Android Gradle Plugin 3.2.0+否则会导致元素点击事件和 Fragment 的页面浏览事件无法触发,App 和 H5 打通功能受影响
  • 插件与 SDK 版本依赖关系:
    在这里插入图片描述

官方配置

project 级别的 build.gradle 文件中添加 android-gradle-plugin2 依赖:

buildscript {
    
    
    repositories {
    
    
		mavenCentral()
        jcenter()
    }
    dependencies {
    
    
		// 添加 gradle 3.2.0+ 依赖
        classpath 'com.android.tools.build:gradle:3.5.3'
        // 添加神策分析 android-gradle-plugin2 依赖
        classpath 'com.sensorsdata.analytics.android:android-gradle-plugin2:3.5.3'
    }
}

主 module(app)build.gradle 文件中应用 com.sensorsdata.analytics.android 插件依赖:

apply plugin: 'com.android.application'
// 应用 com.sensorsdata.analytics.android 插件
apply plugin: 'com.sensorsdata.analytics.android'

dependencies {
    
    
}

主 modulebuild.gradle 文件中添加 SDK 依赖

apply plugin: 'com.android.application'
// 应用 com.sensorsdata.analytics.android 插件
apply plugin: 'com.sensorsdata.analytics.android'

dependencies {
    
    
   // 添加 Sensors Analytics SDK 依赖
   implementation 'com.sensorsdata.analytics.android:SensorsAnalyticsSDK:6.6.7'
}

推荐版本(截止 2023.6.30)

在这里插入图片描述


项目配置

当前项目使用的是kts,非groovy,俩者使用可能稍有区别

build.gradle(project)

@file:Suppress("UnstableApiUsage", "DSL_SCOPE_VIOLATION")

buildscript {
    
    
    dependencies {
    
    
        classpath("com.android.tools.build:gradle:7.4.0")
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21")
        classpath("com.sensorsdata.analytics.android:android-gradle-plugin2:3.5.4")
    }
}

plugins {
    
    
	//若是感觉某个无用,可自行删除
    alias(libs.plugins.android.application) apply false
    alias(libs.plugins.android.library) apply false
    alias(libs.plugins.kotlin.jvm) apply false
    id("org.jetbrains.kotlin.android") version "1.7.21" apply false
}

build.gradle(主 module(app)

plugins {
    
    
    id("haapp.android.application")
    id("com.sensorsdata.analytics.android")
}

build.gradle(module)

哪个模块做相关的初始化操作,就在哪个模块引入 SDK

dependencies {
    
    
    implementation("com.sensorsdata.analytics.android:SensorsAnalyticsSDK:6.6.8")
}

初始化SDK

主要涵盖 官方SDK初始化项目初始化的基础封装

官方初始化

一般金融行业的app会涉及合规的问题,需要确认用户授权后才可使用;
延迟初始化 SDK 会导致全埋点采集不准确和可视化全埋点、点击分析功能异常若 App 有合规需求,可参考 Android 合规步骤

ApplicationonCreate() 方法中同步调用 SensorsDataAPI.startWithConfigOptions() 初始化 SDK:

String SA_SERVER_URL = "数据接收地址";

// 初始化配置
SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL);
// 开启全埋点
saConfigOptions.setAutoTrackEventType(SensorsAnalyticsAutoTrackEventType.APP_CLICK |
                SensorsAnalyticsAutoTrackEventType.APP_START |     
                SensorsAnalyticsAutoTrackEventType.APP_END |       
                SensorsAnalyticsAutoTrackEventType.APP_VIEW_SCREEN)
				//开启 Log
				.enableLog(true);
/**
 * 其他配置,如开启可视化全埋点
 */
// 需要在主线程初始化神策 SDK
SensorsDataAPI.startWithConfigOptions(this, saConfigOptions);

SDK 共需要四个权限:
在这里插入图片描述

SDK 为简化集成步骤,默认在 AndroidManifest.xml 中注册了以上四个权限。如果想要去除 SDK 注册的权限,可以使用 tools:node="remove" 配置。关于 tools:node="remove" 的详细说明可参考谷歌 官方文档,配置代码参考:

<uses-permission android:name="android.permission.READ_PHONE_STATE" tools:node="remove" />

项目初始化

我只用了直接初始化的API(很有限),关于更多的API可以前往 基础 API 功能介绍

可以直接写在 Application 中,这里是封装了一个管理类,可以直接在 Application 中调用 SensorManger.initSetting(context)对应的serviceUrl 地址(上报服务器)需要在神策后台查看一下,也可以让我方运营、神策运营告知一下,因为测试上报的服务器有所不同

import android.app.Activity
import android.app.Application
import android.content.Context
import com.sensorsdata.analytics.android.sdk.SAConfigOptions
import com.sensorsdata.analytics.android.sdk.SensorsAnalyticsAutoTrackEventType
import com.sensorsdata.analytics.android.sdk.SensorsDataAPI
import com.sensorsdata.analytics.android.sdk.core.business.exposure.SAExposureConfig
import org.json.JSONObject
import java.util.concurrent.Executors


internal object SensorManger {
    
    

	// 埋点数据对应的上报服务器,都是需要运营 或 神策方提供
    // 测试
    private const val serviceUrl = "https://xx.com.cn:8888"
    // 生产
    // private const val serviceUrl = "https://xx.com.cn"

    fun initSetting(application: Application) {
    
    
            init(application)
    }

    fun initSetting(activity: Activity) {
    
    
            init(activity)
    }

    private fun init(context: Context) {
    
    
        // 开启全埋点 其他配置,如开启可视化全埋点 需要在主线程初始化神策 SDK
        SensorsDataAPI.startWithConfigOptions(context, SAConfigOptions(serviceUrl).apply {
    
    
            // 开启全埋点
            autoTrackEventType = SensorsAnalyticsAutoTrackEventType.APP_START or
                    SensorsAnalyticsAutoTrackEventType.APP_END
            // 打开 SDK 的日志输出功能
            enableLog(BuildVariants.isDebug())
            // 开启 App 打通 H5
            enableJavaScriptBridge(true)
            // 传入 true 代表开启推送点击事件自动采集
            enableTrackPush(true)
        })
        trackAppInstall(context)
    }

    /**
     * 记录激活事件
     */
    private fun trackAppInstall(context: Context) {
    
    
        try {
    
    
            val properties = JSONObject()
            //这里的 DownloadChannel 负责记录下载商店的渠道,值应传入具体应用商店包的标记。如果没有为不同商店打多渠道包,则可以忽略该属性的代码示例。
            properties.put("DownloadChannel", getChannelName(context))
            // 触发激活事件
            // 如果您之前使用 trackInstallation() 触发的激活事件,需要继续保持原来的调用,无需改为 trackAppInstall(),否则会导致激活事件数据分离。
            SensorsDataAPI.sharedInstance().trackAppInstall(properties)
        } catch (e: Exception) {
    
    
            e.printStackTrace()
        }
    }

    /**
     * 获取渠道名,获取不到默认"android"
     */
    private fun getChannelName(context: Context?): String {
    
    
        var channelName: String? = null
        try {
    
    
            val packageManager: PackageManager? = context?.packageManager
            val applicationInfo: ApplicationInfo? = packageManager?.getApplicationInfo(
                context.packageName,
                PackageManager.GET_META_DATA
            )
            channelName = applicationInfo?.metaData?.get("CHANNEL_ID").toString()
        } catch (e: Exception) {
    
    
            e.printStackTrace()
        }
        return channelName ?: "android"
    }

    private val executor by lazy {
    
     Executors.newSingleThreadExecutor() }

    private fun execute(inv: () -> Unit) {
    
    
        executor.execute {
    
    
            try {
    
    
                inv.invoke()
            } catch (throwable: Throwable) {
    
    
                Timber.e(throwable)
            }
        }
    }

    fun track(eventName: String, properties: Map<String, String?>) = execute {
    
    
        val jsonObject = JSONObject()
        properties.entries.forEach {
    
    
            jsonObject.put(it.key.string(), it.value.string())
        }
        SensorsDataAPI.sharedInstance().track(eventName, jsonObject)
    }
}

配置 Scheme

Scheme 是什么?

  • 是一种页面内跳转协议
  • 通过定义自己的scheme协议,可以非常方便跳转app中的各个页面
  • 通过scheme协议,服务器可以定制化告诉App跳转到APP内部页面

在使用神策系统中的 Debug 实时查看、App 点击分析、可视化全埋点等需要扫码的功能时,需要给某一个 Activity 配置 scheme,配置后扫码即可拉起该 Activity 页面并且与神策系统建立连接使用相关功能。

官方配置

Sdk 5.2.2及以上版本

AndroidManifest 文件中,配置以下 Activity,并将 scheme 的值替换为您项目中的值

<!-- Android 12 需添加 android:exported="true"-->
<activity android:name="com.sensorsdata.analytics.android.sdk.dialog.SchemeActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:launchMode="singleTask">
        <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="您项目的 scheme" />
        </intent-filter>
</activity>

Sdk 5.2.2以下版本

获取 Scheme 后,在 AndroidManifest 文件中的 Activity 标签内配置 Scheme,以 MainActivity 为例:

<activity android:name=".MainActivity">
<!-- 在 MainActivity 中配置 Scheme-->
	<intent-filter>
		<action android:name="android.intent.action.VIEW" />
		<category android:name="android.intent.category.BROWSABLE" />
		<category android:name="android.intent.category.DEFAULT" />
		<data
			android:scheme="您项目的 Scheme 值" />
	</intent-filter>
</activity> 

项目配置

对应的scheme地址需要在神策后台查看一下,也可以让我方运营、神策运营告知一下

在这里插入图片描述

AndroidManifest

    <!-- Android 12 需添加 android:exported="true"-->
    <activity
        android:name="com.sensorsdata.analytics.android.sdk.dialog.SchemeActivity"
        android:configChanges="orientation|screenSize"
        android:exported="true"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.BROWSABLE" />
            <category android:name="android.intent.category.DEFAULT" />
            <!-- 测试 -->
            <data android:scheme="l77777" />
            <!-- 生产 -->
            <!--<data android:scheme="l66666" />-->
        </intent-filter>
    </activity>

打通APP和H5

版本要求

  • Android SDK v4.0.8 及以上版本
  • Android 插件 v3.2.4 及以上版本

初始化 SDK 时,进行如下配置,即可开启 App 打通 H5 功能

// 开启 App 打通 H5
saConfigOptions.enableJavaScriptBridge(boolean isSupportJellyBean);

isSupportJellyBean:是否支持 API level 16 及以下的版本。

打通功能通过 WebView 的 addJavascriptInterface() 方法实现,但在 API level 16 及以下的版本,addJavascriptInterface() 方法有安全漏洞,因此请谨慎使用。

打通功能需要 App 和 H5 同时开启才可以生效,H5 开启方法请 参考 App 打通 H5

  • X5 内核打通,在初始化后添加 SensorsDataAPI.sharedInstance().showUpX5WebView(WebView,true);
  • UC 内核的 WebView 除了上述代码,还需要在插件配置中添加:addUCJavaScriptInterface = true 这个选项,在主 module 级别的 build.gradle 文件中添加我们的扩展如下;
sensorsAnalytics{
    
    
	addUCJavaScriptInterface=true
}

因为项目中正好有这个需求,所以在我们初始化的时候已经开启了这个功能

在这里插入图片描述


实践封装

这儿只做简单封装说明吧,有兴趣的可以去 神策(Android)- 在曝光采集基础上学习项目架构 看一下

StatisticsEvent 单例工具 - 方便调用

object StatisticsEvent {
    
    

    /**
     * 神策埋点:测试
     */
    @JvmStatic
    fun test(param1: String?) {
    
    
        StatisticsService.service.test(param1)
    }
}

StatisticsService 抽象类 - 统计方法

ServiceManager 相关讲解可以去 在曝光采集基础上学习项目架构 看一下,这里就不重复讲究了

interface StatisticsService {
    
    

	// 这里是实例化该Service,因为Hilt原因,采用了注入方式;可自行改为
    companion object {
    
    
        @JvmStatic
        val service: StatisticsService by lazy {
    
     ServiceManager.queryStatisticsService() }
    }

    // 测试
    fun test(param1: String?)
 }

StatisticsServiceImpl 具体类 - 方法实现

internal class StatisticsServiceImpl @Inject constructor() : StatisticsService {
    
    

    override fun track(eventName: String?, properties: MutableMap<String, String?>.() -> Unit) {
    
    
        track(eventName, mutableMapOf<String, String?>().apply(properties))
    }

    override fun track(eventName: String?, properties: Map<String, String?>) {
    
    
        if (eventName.isNullOrEmpty()) return
        SensorManger.track(eventName, properties)
    }
    
    /**
     * 神策埋点:测试
     */
    override fun test(param1: String?) {
    
    
        val properties = mutableMapOf<String, String>()
        properties["param1"] = "下雨天"
        SensorManger.track(EventName.test, properties)
    }
}

EventName 事件名称管理

internal object EventName {
    
    
    const val test: String = "运营提供的埋点事件名称"     // 测试
  }

兴趣环节

StatisticsService 中海油另一种获取接口实例的方式(主要用到了反射,先获取实例,然后通过ARouter传递回去)

    companion object {
    
    
        @JvmStatic
        val service: StatisticsService? by lazy {
    
     ServiceManager.getService(StatisticsService::class.java) }
    }

ServiceManager 获取Service

import com.alibaba.android.arouter.launcher.ARouter

class ServiceManager {
    
    
    companion object {
    
    

        @JvmStatic
        fun <T> getService(service: Class<out T>): T {
    
    
            return ARouter.getInstance().navigation(service)
        }

        @JvmStatic
        fun getService(path: String): Any {
    
    
            return ARouter.getInstance().build(path).navigation()
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_20451879/article/details/131471200