1. Attribute Plugins

Attribute pluginization is an advanced feature provided by the Sensors Analytics Android SDK version 6.4.3 and later, which is used to modify the properties of track-type events. Users can add and delete properties for specific events or add and delete properties for specific event types through attribute plugins.

1.1. Interface Introduction

The SDK provides SAConfigOptions.registerPropertyPlugin() during initialization and SensorsDataAPI.registerPropertyPlugin() after initialization to register custom attribute plugins, which are implemented through SAPropertyPlugin to add properties to specified events. Note that registering in SAConfigOptions at an earlier time ensures that the corresponding properties are added to all filtered events, while registering through SensorsDataAPI may not add the corresponding properties to startup events triggered by delayed initialization.

Introduction to SAPropertyPlugin Class:

Method NameDescription
properties(SAPropertiesFetcher fetcher)

Used to modify properties. Get the property JSONObject collection through fetcher.getProperties() and then modify the properties as needed.

Introduction to SAPropertiesFetcher Class:

Method NameDescription
JSONObject getProperties()Get the JSONObject collection corresponding to the properties attribute. Perform property addition, deletion, modification, and retrieval operations on the JSONObject.
JSONObject getEventJson(String name)                         

Get the corresponding attributes in the form of a JSONObject based on the specified name. Currently supported values for name are SAPropertyFilter.PROPERTIES, SAPropertyFilter.LIB, and SAPropertyFilter.IDENTITIES.

isMatchedWithFilter(SAPropertyFilter filter)

Used to specify the scope of the attribute plugin. The default value is to apply to track-type events.

Introduction to SAPropertyFilter Class:

Method NameDescription
String getEvent()          Get the event name, can be used for filtering events
EventType getType()Get the event type, with values of "track", "track_signup", "track_id_bind", "track_id_unbind", "profile_set", "profile_set_once", "profile_unset", "profile_increment", "profile_append", "profile_delete", "item_set", and "item_delete"
JSONObject getProperties()               Get the properties of the current event, can be used as filtering conditions based on properties
JSONObject getEventJson(String name)Get the corresponding property JSONObject collection based on the specified name, currently supported values of name are: SAPropertyFilter.PROPERTIES, SAPropertyFilter.LIB, and SAPropertyFilter.IDENTITIES
SAPropertyPluginPriority priority()The priority of the property plugin, default value is "Default" (500), the higher the value, the higher the level of property modification
getName()Used to set the name of the property plugin, ensure that the name is unique and not repeatable, the default value is the fully qualified name of the class

1.2. Example

In the example below, filter out the specified event and then add custom properties

saConfigOptions.registerPropertyPlugin(new SAPropertyPlugin() { @Override public boolean isMatchedWithFilter(SAPropertyFilter filter) { // 示例,筛选指定事件名添加属性,默认筛选条件是 track 事件类型 return "指定事件名称".equals(filter.getEvent()); } @Override public void properties(SAPropertiesFetcher fetcher) { try { // 给符合筛选条件的事件添加属性 fetcher.getProperties().put("自定义属性","自定义属性名称"); 			//fetcher.getProperties().remove(key) 删除执行属性 } catch (JSONException e) { e.printStackTrace(); } } });
JAVA

2. Intercept event storage

v3.2.10 and later versions, the SDK can filter event data by using the setTrackEventCallBack() method. The SDK decides whether to store the event based on the return value of the onTrackEvent interface. If it returns true, the current event will be stored and reported normally. If it returns false, it means that the event is discarded.

SensorsDataAPI.sharedInstance().setTrackEventCallBack(new SensorsDataTrackEventCallBack() { 	/** * 事件回调接口 * * @param eventName 事件名称 * @param eventProperties 要修改的事件属性 * @return true 表示事件将入库, false 表示事件将被抛弃 */ 	@Override 	public boolean onTrackEvent(String eventName, JSONObject eventProperties) { 	 		if(eventName.equals("BuyProduct")){ 			// 不要这个埋点了 returen false; 		}	 		// 		return true; 	} });
JAVA

3. Custom caching and encryption

In the basic API introduction document, the SDK cache encryption is encrypted using AES by default. If you need to use other encryption methods, you need to customize it through the cache encryption plugin.

3.1. Interface Introduction

Call the registerStorePlugin interface to register a custom encryption plugin during SDK initialization to enable it.

StorePlugin Class Introduction:

Method NameDescription
setString(String key, String value)Store String type data, and implement the corresponding storage logic
getString(String key)Get String type data based on the specified key, and implement the retrieval logic
setBool(String key, boolean value)Store boolean type data, and implement the corresponding storage logic
getBool(String key)Get boolean type data based on the specified key, and implement the retrieval logic
setInteger(String key, int value)Store int type data, and implement the corresponding storage logic
getInteger(String key)Get int type data based on the specified key, and implement the retrieval logic
setFloat(String key, float value)Store float type data, and implement the corresponding storage logic
getFloat(String key)Get float type data according to the specified key and implement the retrieval logic
setLong(String key, long value)Store long type data and implement the corresponding storage logic
getLong(String key)Get long type data according to the specified key and implement the retrieval logic
remove(String key)Delete the specified key and implement the corresponding logic
type()The name of the attribute plugin, need to implement the corresponding logic
isExists(String key)Check if the specified key exists in the storage file and implement the corresponding logic

When customizing the cache encryption storage plugin, developers need to implement the storage and retrieval of corresponding data types.

3.2. Usage Example

In the following example, the custom encryption plugin is used to implement the GM algorithm encryption.

public class SM4StorePlugin implements StorePlugin { private static final String FILE_NAME = "com.sensorsdata.storePlugin"; private static final String SM4_SECRET = "sm4_key"; private byte[] mSM4KeyBytes; private final SharedPreferences mSPreferences; static { try { Class<?> provider = Class.forName("org.spongycastle.jce.provider.BouncyCastleProvider"); Security.addProvider((Provider) provider.newInstance()); } catch (Exception e) { e.printStackTrace(); } } public SM4StorePlugin(Context context) { mSPreferences = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); try { if (mSPreferences.contains(SM4_SECRET)) { mSM4KeyBytes = Base64Coder.decode(mSPreferences.getString(SM4_SECRET, null)); } if (mSM4KeyBytes == null) { mSM4KeyBytes = generateSymmetricKey(); mSPreferences.edit().putString(SM4_SECRET, new String(Base64Coder.encode(mSM4KeyBytes))).apply(); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } @Override public void upgrade(StorePlugin oldPlugin) { // 升级时的处理操作 } @Override public void setString(String key, String value) { mSPreferences.edit().putString(key, sm4Encrypt(value)).apply(); } @Override public void setBool(String key, boolean value) { mSPreferences.edit().putBoolean(key, value).apply(); } @Override public void setInteger(String key, int value) { mSPreferences.edit().putInt(key, value).apply(); } @Override public void setFloat(String key, float value) { mSPreferences.edit().putFloat(key, value).apply(); } @Override public void setLong(String key, long value) { mSPreferences.edit().putLong(key, value).apply(); } @Override public String getString(String key) { return sm4Decrypt(mSPreferences.getString(key, null)); } @Override public Boolean getBool(String key) { return mSPreferences.getBoolean(key, false); } @Override public Integer getInteger(String key) { return mSPreferences.getInt(key, 0); } @Override public Float getFloat(String key) { return mSPreferences.getFloat(key, 0); } @Override public Long getLong(String key) { return mSPreferences.getLong(key, 0); } @Override public void remove(String key) { mSPreferences.edit().remove(key).apply(); } @Override public boolean isExists(String key) { return mSPreferences.contains(key); } @Override public String type() { return FILE_NAME; } private byte[] generateSymmetricKey() throws NoSuchAlgorithmException { KeyGenerator keyGen = KeyGenerator.getInstance("SM4"); keyGen.init(128); SecretKey aesKey = keyGen.generateKey(); return aesKey.getEncoded(); } /** * 使用 SM4 进行加密 * @return 加密后的数据 */ private String sm4Encrypt(String content) { if (mSM4KeyBytes == null) { return content; } try { Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding"); byte[] ivBytes = new byte[16]; SecretKeySpec secretKeySpec = new SecretKeySpec(mSM4KeyBytes, "SM4"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes)); byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8")); return new String(Base64.encode(encryptedBytes)); } catch (Exception ex) { SALog.printStackTrace(ex); } return content; } private String sm4Decrypt(String content) { try { if (mSM4KeyBytes == null) { return content; } Cipher cipher = Cipher.getInstance("SM4/CBC/PKCS5Padding"); byte[] ivBytes = new byte[16]; SecretKeySpec secretKeySpec = new SecretKeySpec(mSM4KeyBytes, "SM4"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes)); return new String(cipher.doFinal(Base64Coder.decode(content)), "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return content; } }
JAVA

4. Restrict SDK from reading sensitive attributes

This function is used to set sensitive device identifier values for the SDK on the app side and can be used to solve the problem of multiple calls to device identifiers.Currently, the SDK caches information such as the carrier, Android ID, device ID, and MAC address. The cached data is used when the retrieval is successful, and another retrieval attempt is made if it is empty.

This operation is a dangerous operation. Please consult the on-duty colleague for guidance before use.

4.1. Interface Description

Interface Name

Parameter Description

Purpose of the interface

registerLimitKeys(Map&lt;String, String&gt; limitKeys)

Set the collection of restrictive attributesReplace the corresponding interface call by setting the preset value of the restrictive attribute, used to avoid sensitive API calls

Android preset LimitKey

Name

Description

ANDROID_IDAndroid ID, used for $device_id property collection and user identification in anonymous state (distinct_id, AnonymousId). When Android ID is disabled, uuid is used as the user identifier. Dangerous operation, please make sure the value is correct.
CARRIERCarrier, carrier information. Dangerous operation, please make sure the value is correct.
IMEIIMEI number, used for channel matching. Dangerous operation, please make sure the value is correct.
MACMac address, used for channel matching. Dangerous operation, please make sure the value is correct.
OAIDOAID used for channel matching. Dangerous operation, please make sure the value is correct.
MEIDMEID number, used for channel matching. Dangerous operation, please make sure the value is correct.

4.2. Usage Example

注意

AndroidID involves user identification, please make sure to pass it correctly. It is recommended to obtain AndroidID through the interface for obtaining AndroidID provided by Sensors Analytics.


SAConfigOptions configOptions = new SAConfigOptions(SA_SERVER_URL); // 设置限制性属性 Map<String, String> map = new HashMap<>(); map.put(LimitKey.ANDROID_ID, SensorsDataUtils.getIdentifier(this)); map.put(LimitKey.CARRIER, SensorsDataUtils.getOperator(this)); configOptions.registerLimitKeys(map); //传入 SAConfigOptions 对象,初始化神策 SDK SensorsDataAPI.startWithConfigOptions(this, configOptions);
CODE

5. Prohibited to acquire the IMEI number

If you do not want to collect IMEI, you can configure it not to collect through the following configuration. After configuration, the Sensors Analytics plug-in will remove the related code that obtains IMEI during the compilation period.

Configure in the main module's build.gradle:


// 禁止获取 IMEI 号 sensorsAnalytics { sdk { 		disableIMEI = true } }
GROOVY
  1. disableIMEI has a default value of false. If set to true, the IMEI will not be collected, which will affect channel tracking.
  2. This configuration is only applicable to plug-in version v3.0.0 and above.
  3. In the environment before Android Grdle Plugin 3.2.0 (Android Studio 3.2), if you want to use this configuration, you need to manually enable D8 desugaring in gradle.properties: android.enableD8.desugaring = true

6. Prohibited to acquire Android ID

If you do not want to collect Android ID, you can configure it not to collect through the following configuration. After configuration, the Sensors Analytics plug-in will remove the related code that obtains Android ID during the compilation period.

Configure in the main module's build.gradle:

// 禁止获取 Android ID sensorsAnalytics { sdk { 	 disableAndroidID = true } } // 开启获取 Android ID sensorsAnalytics { sdk { 	 disableAndroidID = false } }
GROOVY
  1. disableAndroidID has a default value of false. If set to true, the Android ID will not be collected, which will affect the $device_id event property and channel tracking.
  2. This configuration is only applicable to plug-in version v3.0.0 and above.
  3. In the environment before Android Grdle Plugin 3.2.0 (Android Studio 3.2), if you want to use this configuration, you need to manually enable D8 desugaring in gradle.properties: android.enableD8.desugaring = true

7. Prohibited to acquire OAID

If not collect OAID, the following configurations do not collect data, This configuration deletes the contents of OaidHelper.getOAID, uniformly returning an empty string

Inmain Module build.gradle configure:

// 禁止获取 OAID sensorsAnalytics { sdk { disableOAID = true } }
GROOVY
  1. disableOAID default value is false,If setted as true ,OAID will not be collected.
  2. This configuration is only applicable to plugin version v3.4.7 and above.
  3. In the environment of Android Grdle Plugin 3.2.0 (Android Studio 3.2) and earlier versions, you need to manually enable the desugaring configuration in gradle.properties: android.enableD8.desugaring = true

8. Prohibit obtaining the MacAddress.

If you do not want to collect MacAddress, you can configure it to not collect it. After configuration, the Sensors Analytics plugin will remove the relevant code for obtaining the mac address during compilation.

Configure in the main Module's build.gradle:

// 禁止获取 MacAddress sensorsAnalytics { sdk { 	 disableMacAddress = true } }
GROOVY
  1. The default value of disableMacAddress is false. If set to true, the mac address will not be collected, which will affect channel tracking.
  2. This configuration is only applicable to plugin version v3.0.0 and above.
  3. In the environment of Android Grdle Plugin 3.2.0 (Android Studio 3.2) and earlier versions, you need to manually enable the desugaring configuration in gradle.properties: android.enableD8.desugaring = true