Android 전매점 - 페이지 탐색 이벤트

11551 단어
전매점
전매점도 무매점이라고 하는데, 자동매점이라고 한다.사용자의 모든 행위 데이터를 미리 자동으로 수집하는 것을 말한다.그리고 수집된 데이터에 따라 필요한 행위 데이터를 선별하여 분석할 수 있다.
채집된 이벤트 유형
전매점에서 채집하는 사건은 주로 다음과 같은 4가지 유형을 포함한다.
AppStart 이벤트
응용 프로그램의 시작을 가리키며, 냉각 시작과 열 시작을 포함한다.
AppEnd 이벤트
프로그램이 종료되는 것을 가리킨다. 프로그램의 정상적인 종료, 홈 키가 백엔드에 들어가고, 프로그램이 강살되고, 프로그램이 붕괴되는 것을 포함한다.
AppViewScreen 이벤트
응용 프로그램 페이지 탐색을 가리키며 안드로이드 응용 프로그램에서는Activity나Fragment의 전환을 가리킨다.
AppClick 이벤트
프로그램 컨트롤의 클릭 이벤트, 즉 View의 클릭 이벤트를 가리킨다.
AppViewScreen 전매점 방안
페이지 조회 이벤트는 서로 다른 Activity나Fragment를 전환하는 것을 말한다. Activity에 대한 방법onResume()은 이 페이지가 이미 표시되었음을 의미한다. 즉, 이 페이지가 조회되었다는 것이다.그래서 우리는 onResume() 방법에서 AppViewScreen 이벤트와 관련된 코드를 자동으로 처리하면 AppViewScreen 이벤트의 전매점을 해결할 수 있다.
Application.ActivityLifecycleCallbacks ActivityLifecycleCallbacksApplication의 내부 인터페이스로 API14(Android4.0)부터 제공된다.Application류는 이 인터페이스를 통해 일련의 리셋 방법을 제공하여 개발자가 Activity의 모든 생명주기 사건을 집중적으로 처리할 수 있도록 한다.** Application**에서 제공하는 registerActivityLifecycleCallbacks 방법으로 ActivityLifecycleCallbacks 콜백을 등록할 수 있습니다.
이 인터페이스에서 사용할 수 있는 방법을 살펴보겠습니다.
public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}

ActivityonResume() 방법의 예를 들어 만약에 우리가 이 인터페이스를 등록했다면 안드로이드 시스템은Activity Lifecycle CallbacksonActivityResumed(Activity activity) 방법을 먼저 리셋한 다음Activity 자체onResume() 방법을 실행할 것이다.(참고: 하나의 Application은 여러 개의ActivityLifecycleCallbacks 콜백을 등록할 수 있습니다)
이 방법을 사용하는 것 외에, 우리는BaseActivity를 정의한 다음에 다른Activity가 이BaseActivity를 계승하도록 생각할 수도 있습니다.근데 이게 문제가 될 거예요.만약에 우리가 응용 프로그램에 제3자 라이브러리를 통합하고 제3자 라이브러리의Activity를 사용한다면 우리는 이 페이지의 조회 이벤트를 감시할 수 없다.사용자가 정의한 BaseActivity를 계승할 수 없기 때문입니다.그래서 우리는 Application을 채택한다.Activity Lifecycle Callbacks, 그러나 이 방안은 API14+가 필요하지만, 현재 주류 기종은 모두 만족합니다.
코드 실전
1. 이벤트를 수집하는 데 사용할 도구류 SensorsDataAPI를 정의합니다.
//      
class SensorsDataAPI private constructor(application: Application) {

    //  ID
    private var mDeviceId: String = SensorsDataPrivate.getAndroidID(application.applicationContext)
    //      ,eg:  ,  ,    
    private var mDeviceInfo: Map = SensorsDataPrivate.getDeviceInfo(application.applicationContext)

    companion object {
        //          
        const val SDK_VERSION = "1.0.0"
        @Volatile
        var instance: SensorsDataAPI? = null
        private val TAG = this.javaClass.simpleName

        /**
         *      
         * @param application:Application
         */
        fun init(application: Application) = instance ?: synchronized(this) {
            //        
            instance ?: SensorsDataAPI(application).also { instance = it }
        }
    }

    init {
        //  registerActivityLifecycleCallbacks
        SensorsDataPrivate.registerActivityLifecycleCallbacks(application)
    }

    /**
     *     
     * @param eventName:    
     * @param properties:        
     */
    fun track(@NonNull eventName: String, @Nullable properties: JSONObject?) {
        try {
            val jsonObject = JSONObject()
            jsonObject.put("event", eventName)
            jsonObject.put("device_id", mDeviceId)
            val sendProperties = JSONObject(mDeviceInfo)
            if (properties != null) {
                SensorsDataPrivate.mergeJSONObject(properties, sendProperties)
            }
            jsonObject.put("properties", sendProperties)
            jsonObject.put("time", System.currentTimeMillis())
            Log.e(TAG, jsonObject.toString())
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     *              
     * @param activity :   Activity
     */
    fun ignoreAutoTrackActivity(activity: Class) {
        SensorsDataPrivate.ignoreAutoTrackActivity(activity)
    }

    /**
     *               
     * @param activity
     */
    fun removeIgnoredActivity(activity: Class) {
        SensorsDataPrivate.removeIgnoredActivity(activity)
    }
    
}

SensorsDataPrivate
class SensorsDataPrivate {

    companion object {

        private val mDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.CHINA)
        private val mIgnoredActivities = ArrayList()

        /**
         *         
         * @param activity
         */
        fun trackAppViewScreen(activity: Activity) {
            try {
                if (mIgnoredActivities.contains(activity.javaClass.canonicalName)) {
                    return
                }
                val properties = JSONObject()
                properties.put("activity", activity.javaClass.canonicalName)
                SensorsDataAPI.instance?.track("AppViewScreen", properties)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        /**
         *   androidID
         * @param context
         * @return String
         */
        @SuppressLint("HardwareIds")
        fun getAndroidID(context: Context): String {
            var androidID = ""
            try {
                androidID = Settings.Secure.getString(
                    context.contentResolver,
                    Settings.Secure.ANDROID_ID
                )
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return androidID
        }

        /**
         *         
         * @param context
         * @return Map
         */
        fun getDeviceInfo(context: Context): Map {
            val deviceInfo = HashMap()
            deviceInfo["lib"] = "Android"
            deviceInfo["lib_version"] = SensorsDataAPI.SDK_VERSION
            deviceInfo["os"] = "Android"
            deviceInfo["os_version"] = Build.VERSION.RELEASE ?: "UNKNOWN"
            deviceInfo["manufacturer"] = Build.MANUFACTURER ?: "UNKNOWN"
            deviceInfo["model"] = if (TextUtils.isEmpty(Build.MODEL)) "UNKNOWN" else Build.MODEL.trim()
            try {
                val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
                deviceInfo["app_version"] = packageInfo.versionName
                deviceInfo["app_name"] = context.resources.getString(packageInfo.applicationInfo.labelRes)
            } catch (e: Exception) {
                e.printStackTrace()
            }
            val displayMetrics = context.resources.displayMetrics
            deviceInfo["screen_width"] = displayMetrics.widthPixels
            deviceInfo["screen_height"] = displayMetrics.heightPixels
            //        map
            return Collections.unmodifiableMap(deviceInfo)
        }

        /**
         *   Application.registerActivityLifecycleCallbacks
         * @param application
         */
        fun registerActivityLifecycleCallbacks(application: Application) {
            application.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
                override fun onActivityPaused(activity: Activity?) { }

                override fun onActivityResumed(activity: Activity?) {
                    if (activity != null) {
                        trackAppViewScreen(activity)
                    }
                }

                override fun onActivityStarted(activity: Activity?) { }

                override fun onActivityDestroyed(activity: Activity?) {}

                override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) { }

                override fun onActivityStopped(activity: Activity?) { }

                override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) { }

            })
        }

        /**
         *               
         * @param source     
         * @param dest :    
         */
        fun mergeJSONObject(source: JSONObject, dest: JSONObject) {
            val propertiesIterator = source.keys()
            while (propertiesIterator.hasNext()) {
                val key = propertiesIterator.next()
                val value = source.get(key)
                if (value is Date) {
                    synchronized(mDateFormat) {
                        dest.put(key, mDateFormat.format(value))
                    }
                } else {
                    dest.put(key, value)
                }
            }
        }

        /**
         *        Activity
         * @param activity
         */
        fun ignoreAutoTrackActivity(activity: Class) {
            mIgnoredActivities.add(activity.canonicalName)
        }

        /**
         *      Activity
         * @param activity
         */
        fun removeIgnoredActivity(activity: Class) {
            if (mIgnoredActivities.contains(activity.canonicalName)) {
                mIgnoredActivities.remove(activity.canonicalName)
            }
        }
    }
}

2. Application에서 매점 도구 클래스를 초기화합니다.
SensorsDataAPI.init(this)

참고: AndroidManifest.xml에 Application을 지정하는 것을 잊지 마십시오.
위의 코드 설정을 통해 우리는 페이지를 시작할 때 자동으로 설정된 데이터를 수집합니다. 여기는 단지 로그 형식으로 수집한 데이터를 출력할 뿐입니다.
Log.e(TAG, jsonObject.toString())
{
    "event": "AppViewScreen",
    "device_id": "9e3077550b446ff0",
    "properties": {
        "app_name": "My Application",
        "screen_width": 1080,
        "screen_height": 1794,
        "lib": "Android",
        "os": "Android",
        "app_version": "1.0",
        "os_version": "9",
        "model": "Android SDK built for x86",
        "lib_version": "1.0.0",
        "manufacturer": "Google",
        "activity": "com.example.myapplication.MainActivity"
    },
    "time": 1563692439349
}

SensorsDataAPI에는 ignoreAutoTrackActivityremoveIgnoredActivity가 위의 예에서 사용되지 않은 두 가지 방법이 있다.이 두 가지 방법을 통해 사건의 채집을 무시하고 복구할 수 있다.
예: Android6.0+ 일부 권한은 동적 신청이 필요합니다. 사용자가 허용하든 금지하든 시스템은 현재ActivityonResume() 방법을 다시 리셋합니다.이렇게 하면 다시 페이지 조회 이벤트를 촉발할 수 있기 때문에 권한을 신청해야 하는 페이지에서는 현재의Activity를 무시하고 권한 신청이 끝난 후에 채집을 복원해야 한다.
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
    SensorsDataAPI.instance?.ignoreAutoTrackActivity(MainActivity::class.java)
    when (requestCode) {
        //         
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}

override fun onStop() {
    super.onStop()
    SensorsDataAPI.instance?.removeIgnoredActivity(MainActivity::class.java)
}

페이지 조회 이벤트는 다른 이벤트의 매립점에 비해 비교적 쉽다. 주로 ApplicationActivityLifecycleCallbacks을 통해Activity의 생명주기 관련 방법의 리셋을 감시하여 매립점의 논리를 실현한다.
Kotlin 실전

좋은 웹페이지 즐겨찾기