diff --git a/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml b/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml
index ccba7b4bd8aebe6e15db0be796f443335a7d369c..876067d518d6dd1eb4ac3516dfffe6b345909805 100644
--- a/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml
+++ b/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml
@@ -3,12 +3,16 @@
package="cn.com.mma.mobile.tracking.demo">
-
+
+
+
+
+
();
sdkConfig = sdk;
-
- if (sdkConfig == null) sdkConfig = SdkConfigUpdateUtil.getSdk(context);
-
abilityConfig = initViewAbilityGlobalConfig();
viewAbilityService = new ViewAbilityService(context, mmaSdkCallback, abilityConfig);
-
- viewAbilityJsService = new ViewAbilityJsService(context, sdkConfig);
+ viewAbilityJsService = new ViewAbilityJsService(context);
}
+ /**
+ * 初始化可视化配置,网络动态更新,需要下次启动时生效
+ * @return
+ */
private ViewAbilityConfig initViewAbilityGlobalConfig() {
ViewAbilityConfig config = new ViewAbilityConfig();
@@ -454,6 +454,8 @@ public class ViewAbilityHandler {
return company;
}
}
+ } else {//如果配置缺失,重新获取
+ sdkConfig = SdkConfigUpdateUtil.getSDKConfig(context);
}
return null;
@@ -545,6 +547,9 @@ public class ViewAbilityHandler {
String exposeDuration = "";
String filterURL = adURL;
+ //如果缺失viewabilityargument配置项,直接返回
+ if (arguments == null) return filterURL;
+
//去掉viewabilityarguments中的参数
for (String argumentKey : arguments.keySet()) {
if (!TextUtils.isEmpty(argumentKey)) {
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/AppListUploader.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/AppListUploader.java
index 8a8666c1e8c0846f623ba4c8375bad5f74c6856a..baafb1f906ac4b20baf4591197ed92dc0d842fe5 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/AppListUploader.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/AppListUploader.java
@@ -24,16 +24,23 @@ public class AppListUploader {
private static AppListUploader mInstance = null;
private static boolean isUploading;
private static Context mContext;
+ private long lastUploadTime;
+
private static final String JSON_MAC = "mac";
private static final String JSON_IMEI = "imei";
private static final String JSON_ANDROIDID = "androidid";
private static final String JSON_TIME = "time";
private static final String JSON_APPLIST = "applist";
+ private static final String JSON_SOURCE = "sdk";
+ private static final String JSON_SDKV = "sdkv";
+ private static final String JSON_BUNDLEID = "bundleid";
+ private static final String SOURCE_TYPE = "MMASDK";
private AppListUploader(Context context) {
mContext = context;
+ lastUploadTime = -1;
}
public static AppListUploader getInstance(Context context) {
@@ -70,13 +77,16 @@ public class AppListUploader {
//上一次上报时间=company+identifier
final String spName = company.domain.url + SharedPreferencedUtil.SP_OTHER_KEY_LASTUPLOADTIME_SUFFIX;
- long lastuploadTime = SharedPreferencedUtil.getLong(mContext, SharedPreferencedUtil.SP_NAME_OTHER, spName);
+ if (lastUploadTime < 0) {
+ lastUploadTime = SharedPreferencedUtil.getLong(mContext, SharedPreferencedUtil.SP_NAME_OTHER, spName);
+ }
+
long freq = applistConfig.uploadTime * 60 * 60;//转化成秒
final long currentTime = System.currentTimeMillis() / 1000;
- if (currentTime > (lastuploadTime + freq)) {
+ if (currentTime > (lastUploadTime + freq)) {
String configURL;
@@ -106,6 +116,10 @@ public class AppListUploader {
Map deviceParams = DeviceInfoUtil.getDeviceInfo(mContext);
json.put(JSON_TIME, String.valueOf(System.currentTimeMillis()));
+ json.put(JSON_SOURCE, SOURCE_TYPE);
+ json.put(JSON_BUNDLEID, mContext.getPackageName());
+ json.put(JSON_SDKV, Constant.TRACKING_SDKVS_VALUE);
+
json.put(JSON_MAC, CommonUtil.md5(deviceParams.get(Constant.TRACKING_MAC)));
json.put(JSON_IMEI, CommonUtil.md5(deviceParams.get(Constant.TRACKING_IMEI)));
json.put(JSON_ANDROIDID, CommonUtil.md5(deviceParams.get(Constant.TRACKING_ANDROIDID)));
@@ -122,11 +136,12 @@ public class AppListUploader {
byte[] response = ConnectUtil.getInstance().performPost(uploadURL, encodeData,company.applist.useGzip);
if (response != null) {
//update lastuploadtime
+ lastUploadTime = currentTime;
SharedPreferencedUtil.putLong(mContext, SharedPreferencedUtil.SP_NAME_OTHER, spName, currentTime);
}
}
- } catch (JSONException e) {
+ } catch (Exception e) {
} finally {
isUploading = false;
}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationCollector.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationCollector.java
new file mode 100644
index 0000000000000000000000000000000000000000..97f5c1077ee8ce32b33eb39b0e80d7e29c025579
--- /dev/null
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationCollector.java
@@ -0,0 +1,225 @@
+package cn.com.mma.mobile.tracking.util;
+
+import android.Manifest;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.text.TextUtils;
+import java.util.List;
+
+
+/**
+ * LBS 定位相关数据的采集管理
+ */
+public class LocationCollector {
+
+ private LocationManager locationManager;
+ private static LocationCollector mInstance = null;
+ private Context mContext;
+ private boolean isSynced;
+ //private static final String TAG = "LocationCollector";
+
+ /* 是否使用 位置变更监听器 */
+ private static final boolean ENABLE_LOCATION_UPDATELISTENER = true;
+ /* 位置更新最小时间间隔 单位毫秒 默认300s*/
+ private static final long LOCATION_UPDATE_MINTIME = 300*1000l;
+ /* 位置更新最小距离 单位m 默认100M*/
+ private static final float LOCATION_UPDATE_MINDISTANCE = 0f;
+
+ /* 位置更新时间间隔 单位毫秒 120s*/
+ private static final long UPDATES_INTERVAL = 120 * 1000l;
+ /* 移除更新时间 单位毫秒 20s*/
+ private static final long REMOVE_INTERVAL = 20 * 1000l;
+
+
+ /* 上一次成功获取位置时的时间*/
+ private long lastLocationTime = 0;
+
+ private Location currentLocation;
+ private static Handler mHandler;
+
+
+
+ private LocationCollector(Context context) {
+ mContext = context;
+ isSynced = false;
+ currentLocation = null;
+ locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ public static LocationCollector getInstance(Context context) {
+ if (mInstance == null) {
+ synchronized (LocationCollector.class) {
+ if (mInstance == null) {
+ mInstance = new LocationCollector(context);
+ }
+ }
+ }
+ return mInstance;
+ }
+
+
+
+
+
+ public String getLocation() {
+ if (currentLocation == null) {
+ //Log.w(TAG, "Location is empty,return null,start get syncLocation");
+ syncLocation();
+ return "";
+ } else {
+
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - lastLocationTime) > UPDATES_INTERVAL) {
+ //Log.i(TAG, "Location is expired,start update syncLocation");
+ //更新位置
+ syncLocation();
+ }
+
+ StringBuffer location = new StringBuffer();
+ try {
+ location.append(currentLocation.getLatitude());
+ location.append("x");
+ location.append(currentLocation.getLongitude());
+ location.append("x");
+ location.append(currentLocation.getAccuracy());
+ } catch (Exception e) {
+ }
+
+ return location.toString();//String.format("%fx%fx%f", latitude, longitude, accuracy);
+ }
+
+ }
+
+
+
+ /**
+ * 注册Location Update
+ */
+ public void syncLocation() {
+ try {
+
+ //require ACCESS_FINE_LOCATION and ACCESS_FINE_LOCATION
+ if (Reflection.checkPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) && Reflection.checkPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION)) {
+ //long start = System.currentTimeMillis();
+ //获取所有可用的位置提供器
+ List providers = locationManager.getProviders(true);
+ String locationProvider = null;
+ Location location = null;
+
+ if (providers.contains(LocationManager.GPS_PROVIDER)) {
+ //如果是GPS
+ locationProvider = LocationManager.GPS_PROVIDER;
+ location = locationManager.getLastKnownLocation(locationProvider);
+ }
+
+ if (location == null && providers.contains(LocationManager.NETWORK_PROVIDER)) {
+ locationProvider = LocationManager.NETWORK_PROVIDER;
+ location = locationManager.getLastKnownLocation(locationProvider);
+ }
+
+ if (TextUtils.isEmpty(locationProvider)) {
+ //Log.w(TAG, "no available Location Provider!");
+ return;
+ }
+
+ //Log.d(TAG, "locationProvider:" + locationProvider + " LastKnownLocation is :" + location);
+
+ if (location != null) {
+ //不为空,显示地理位置经纬度
+ //long end = System.currentTimeMillis();
+ //String cost = String.valueOf(end - start) + " ms";
+ //Log.d(TAG, "cost:" + cost + " lat:" + location.getLatitude() + " lon:" + location.getLongitude() + " acc:" + location.getAccuracy() + " time:" + location.getTime());
+ currentLocation = location;
+ lastLocationTime = System.currentTimeMillis();
+ }
+
+ if (ENABLE_LOCATION_UPDATELISTENER && !isSynced) {
+
+ //Logger.e("request Location Updates:" + lastLocationTime + ",mintime:" + LOCATION_UPDATE_MINTIME + ",distance:" + LOCATION_UPDATE_MINDISTANCE);
+
+ final String provider = locationProvider;
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ locationManager.requestLocationUpdates(provider, LOCATION_UPDATE_MINTIME, LOCATION_UPDATE_MINDISTANCE, locationListener);
+ }
+ });
+
+ isSynced = true;
+ //10ms 后停止更新Location
+ mHandler.postDelayed(stopListener, REMOVE_INTERVAL);
+ }
+
+ }
+
+
+ } catch (Exception e) {
+ isSynced = false;
+ }
+
+ }
+
+
+
+ private final Runnable stopListener = new Runnable() {
+ @Override
+ public void run() {
+ //Log.e(TAG, "remove Location Updates:" + lastLocationTime);
+ locationManager.removeUpdates(locationListener);
+ isSynced = false;
+ mHandler.removeCallbacks(stopListener);
+ }
+ };
+
+
+ private LocationListener locationListener = new LocationListener() {
+
+ @Override
+ public void onLocationChanged(Location location) {
+ //Log.i(TAG, "onLocationChanged:" + location + " t:" + location.getTime());
+ //位置发生变化
+ lastLocationTime = System.currentTimeMillis();
+ currentLocation = location;
+
+ }
+
+ @Override
+ public void onStatusChanged(String s, int i, Bundle bundle) {
+ //Location Provider状态改变
+ //Log.i(TAG, "onStatusChanged:" + s + " i:" + i);
+ }
+
+ @Override
+ public void onProviderEnabled(String s) {
+ //Provider可用
+ //Log.i(TAG, "onProviderEnabled:" + s);
+ }
+
+ @Override
+ public void onProviderDisabled(String s) {
+ //Provider不可用
+ //Log.i(TAG, "onProviderDisabled:" + s);
+ }
+ };
+
+ /**
+ * 停止监听位置信息
+ */
+ public void stopSyncLocation() {
+ if (locationManager != null) {
+ locationManager.removeUpdates(locationListener);
+ mHandler.removeCallbacks(stopListener);
+ }
+ }
+
+
+
+
+}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationUtil.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationUtil.java
deleted file mode 100644
index afec3a4b2c250168c30403eca63dfe779ee90d7d..0000000000000000000000000000000000000000
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationUtil.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package cn.com.mma.mobile.tracking.util;
-
-import android.content.Context;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.os.Bundle;
-import cn.com.mma.mobile.tracking.api.Constant;
-
-public class LocationUtil {
-
- private LocationManager locationManager;
-
- private static LocationUtil locationUtil = null;
- private StringBuilder locationBuilder = new StringBuilder();
-
- public String getLocation() {
- return locationBuilder.toString();
- }
-
- private LocationUtil(Context context) {
- locationManager = (LocationManager) context
- .getSystemService(Context.LOCATION_SERVICE);
- }
-
- public static LocationUtil getInstance(Context context) {
- if (locationUtil == null) {
- locationUtil = new LocationUtil(context);
- }
- return locationUtil;
- }
-
- /**
- * 位置监听
- */
- public LocationListener listener = new LocationListener() {
-
- public void onStatusChanged(String s, int i, Bundle bundle) {
- Logger.d("onStatusChanged:" + s);
-
- }
-
- public void onProviderEnabled(String s) {
- Logger.d("onProviderEnabled:" + s);
-
- }
-
- public void onProviderDisabled(String s) {
- Logger.d("onProviderDisabled:" + s);
- }
-
- public void onLocationChanged(Location location) {
- double longitude = location.getLongitude();
- double latitude = location.getLatitude();
- Logger.d(latitude + "x" + longitude);
- locationBuilder = locationBuilder.append(latitude).append("x")
- .append(longitude);
- }
- };;
-
- /**
- * 获得当前地理位置信息及准确程度
- *
- * @param context
- * @param requestUpdate
- * @return
- */
- public void startLocationListener() {
- try {
- Criteria criteria = new Criteria();
- criteria.setAccuracy(Criteria.ACCURACY_COARSE);
- criteria.setAltitudeRequired(false);
- criteria.setBearingRequired(false);
- criteria.setCostAllowed(true);
- criteria.setPowerRequirement(Criteria.POWER_LOW);
- String provider = locationManager.getBestProvider(criteria, true);
- locationManager.requestLocationUpdates(provider,
- Constant.LOCATIOON_UPDATE_INTERVAL, 0, listener);
- } catch (Exception e) {
- Logger.d("mma_Error data LBS" + e);
- e.printStackTrace();
- }
- }
-
- /**
- * 停止监听位置信息
- *
- * @param context
- */
- public void stopListenLocation() {
- if (locationManager != null) {
- locationManager.removeUpdates(listener);
- Logger.d("停止位置监听");
- }
- }
-}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Logger.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Logger.java
index 6e55152a5fdcf97fc508956049a2dead6c4158a7..9d3e63ea8e384d9e1d146902a6045c247386e94f 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Logger.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Logger.java
@@ -36,4 +36,9 @@ public final class Logger {
if (DEBUG_LOG)
Log.w(TAG, msg);
}
+
+ public static void i(String msg) {
+ if (DEBUG_LOG)
+ Log.i(TAG, msg);
+ }
}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Reflection.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Reflection.java
index 21f30a4320a86ea7c0b94f1be377c9b512b69fd1..d772367a74ea0f43ab88d91a2796569abbef3963 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Reflection.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/Reflection.java
@@ -1,144 +1,162 @@
package cn.com.mma.mobile.tracking.util;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-
import android.content.Context;
+import android.content.pm.PackageManager;
public class Reflection {
- public static String getPlayAdId(Context context) {
- try {
- boolean isGooglePlayServicesAvailable = Reflection.isGooglePlayServicesAvailable(context);
- if(isGooglePlayServicesAvailable){
- Object AdvertisingInfoObject = getAdvertisingInfoObject(context);
- String playAdid = (String) invokeInstanceMethod(
- AdvertisingInfoObject, "getId", null);
- return playAdid;
- }else{
- Logger.e("google play service is missing!!!");
- return "";
- }
-
-
- } catch (Throwable t) {
- return "";
- }
- }
-
- public static boolean isGooglePlayServicesAvailable(Context context) {
- try {
- Integer isGooglePlayServicesAvailableStatusCode = (Integer) invokeStaticMethod(
- "com.google.android.gms.common.GooglePlayServicesUtil",
- "isGooglePlayServicesAvailable",
- new Class[] { Context.class }, context);
-
- boolean isGooglePlayServicesAvailable = (Boolean) isConnectionResultSuccess(isGooglePlayServicesAvailableStatusCode);
-
- return isGooglePlayServicesAvailable;
- } catch (Throwable t) {
- return false;
- }
- }
-
- public static String getMacAddress(Context context) {
- try {
- String macSha1 = (String) invokeStaticMethod(
- "com.adjust.sdk.plugin.MacAddressUtil", "getMacAddress",
- new Class[] { Context.class }, context);
-
- return macSha1;
- } catch (Throwable t) {
- return null;
- }
- }
-
- private static Object getAdvertisingInfoObject(Context context)
- throws Exception {
- return invokeStaticMethod(
- "com.google.android.gms.ads.identifier.AdvertisingIdClient",
- "getAdvertisingIdInfo", new Class[] { Context.class }, context);
- }
-
- private static boolean isConnectionResultSuccess(Integer statusCode) {
- if (statusCode == null) {
- return false;
- }
-
- try {
- Class ConnectionResultClass = Class
- .forName("com.google.android.gms.common.ConnectionResult");
-
- Field SuccessField = ConnectionResultClass.getField("SUCCESS");
-
- int successStatusCode = SuccessField.getInt(null);
-
- return successStatusCode == statusCode;
- } catch (Throwable t) {
- return false;
- }
- }
-
- public static Class forName(String className) {
- try {
- Class classObject = Class.forName(className);
- return classObject;
- } catch (Throwable t) {
- return null;
- }
- }
-
- public static Object createDefaultInstance(String className) {
- Class classObject = forName(className);
- Object instance = createDefaultInstance(classObject);
- return instance;
- }
-
- public static Object createDefaultInstance(Class classObject) {
- try {
- Object instance = classObject.newInstance();
- return instance;
- } catch (Throwable t) {
- return null;
- }
- }
-
- public static Object createInstance(String className, Class[] cArgs,
- Object... args) {
- try {
- Class classObject = Class.forName(className);
- @SuppressWarnings("unchecked")
- Constructor constructor = classObject.getConstructor(cArgs);
- Object instance = constructor.newInstance(args);
- return instance;
- } catch (Throwable t) {
- return null;
- }
- }
-
- public static Object invokeStaticMethod(String className,
- String methodName, Class[] cArgs, Object... args) throws Exception {
- Class classObject = Class.forName(className);
-
- return invokeMethod(classObject, methodName, null, cArgs, args);
- }
-
- public static Object invokeInstanceMethod(Object instance,
- String methodName, Class[] cArgs, Object... args) throws Exception {
- Class classObject = instance.getClass();
-
- return invokeMethod(classObject, methodName, instance, cArgs, args);
- }
-
- public static Object invokeMethod(Class classObject, String methodName,
- Object instance, Class[] cArgs, Object... args) throws Exception {
- @SuppressWarnings("unchecked")
- Method methodObject = classObject.getMethod(methodName, cArgs);
-
- Object resultObject = methodObject.invoke(instance, args);
-
- return resultObject;
- }
+
+
+
+ public static boolean checkPermission(Context context, String permission) {
+ // 使用反射,以免因没有导入新的v4包找不到ContextCompat而崩溃
+// int result = 0;
+// if (getContextCompat()) {
+// result = getContextCompatValue(context, permission);
+// }
+// return result == PackageManager.PERMISSION_GRANTED;
+ return getContextCompat() ? getContextCompatValue(context, permission) == PackageManager.PERMISSION_GRANTED : false;
+
+ }
+
+
+ public static String getPlayAdId(Context context) {
+
+ boolean isGooglePlayServicesAvailable = isGooglePlayServicesAvailable(context);
+ if (!isGooglePlayServicesAvailable) Logger.w("googlePlay service is unavailable!");
+
+ String playAdid = null;
+ try {
+ Object advertisingObject = getAdvertisingInfoObject(context);
+ if (advertisingObject != null) {
+ playAdid = (String) invokeInstanceMethod(advertisingObject, "getId", null);
+ }
+ } catch (Throwable t) {
+
+ }
+ return playAdid == null ? "" : playAdid;
+ }
+
+
+
+
+ private static boolean getContextCompat() {
+ try {
+ Class> classObject = Class.forName("android.support.v4.content.ContextCompat");
+ if (classObject != null) {
+ return true;
+ }
+ } catch (Exception e) {
+ }
+ return false;
+ }
+
+ private static int getContextCompatValue(Context ctx, String permissions) {
+ try {
+ Class> classObject = Class.forName("android.support.v4.content.ContextCompat");
+ Method staticMethod = classObject.getDeclaredMethod("checkSelfPermission", Context.class, String.class);
+ return (Integer) staticMethod.invoke(classObject, ctx, permissions);
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+
+ private static boolean isGooglePlayServicesAvailable(Context context) {
+ try {
+ Integer isGooglePlayServicesAvailableStatusCode = (Integer) invokeStaticMethod(
+ "com.google.android.gms.common.GooglePlayServicesUtil", "isGooglePlayServicesAvailable",
+ new Class[]{Context.class}, context);
+
+ boolean isGooglePlayServicesAvailable = isConnectionResultSuccess(isGooglePlayServicesAvailableStatusCode);
+
+ return isGooglePlayServicesAvailable;
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+
+ private static Object getAdvertisingInfoObject(Context context) throws Exception {
+ return invokeStaticMethod("com.google.android.gms.ads.identifier.AdvertisingIdClient",
+ "getAdvertisingIdInfo",
+ new Class[]{Context.class}, context);
+ }
+
+ private static boolean isConnectionResultSuccess(Integer statusCode) {
+ if (statusCode == null) {
+ return false;
+ }
+
+ try {
+ Class ConnectionResultClass = Class.forName("com.google.android.gms.common.ConnectionResult");
+
+ Field SuccessField = ConnectionResultClass.getField("SUCCESS");
+
+ int successStatusCode = SuccessField.getInt(null);
+
+ return successStatusCode == statusCode;
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+// public static Class forName(String className) {
+// try {
+// Class classObject = Class.forName(className);
+// return classObject;
+// } catch (Throwable t) {
+// return null;
+// }
+// }
+
+// public static Object createDefaultInstance(String className) {
+// Class classObject = forName(className);
+// Object instance = createDefaultInstance(classObject);
+// return instance;
+// }
+//
+// public static Object createDefaultInstance(Class classObject) {
+// try {
+// Object instance = classObject.newInstance();
+// return instance;
+// } catch (Throwable t) {
+// return null;
+// }
+// }
+
+// public static Object createInstance(String className, Class[] cArgs, Object... args) {
+// try {
+// Class classObject = Class.forName(className);
+// Constructor constructor = classObject.getConstructor(cArgs);
+// Object instance = constructor.newInstance(args);
+// return instance;
+// } catch (Throwable t) {
+// return null;
+// }
+// }
+
+ private static Object invokeStaticMethod(String className, String methodName, Class[] cArgs, Object... args) throws Exception {
+ Class classObject = Class.forName(className);
+
+ return invokeMethod(classObject, methodName, null, cArgs, args);
+ }
+
+ private static Object invokeInstanceMethod(Object instance, String methodName, Class[] cArgs, Object... args) throws Exception {
+ Class classObject = instance.getClass();
+
+ return invokeMethod(classObject, methodName, instance, cArgs, args);
+ }
+
+ private static Object invokeMethod(Class classObject, String methodName, Object instance, Class[] cArgs, Object... args) throws Exception {
+
+ Method methodObject = classObject.getMethod(methodName, cArgs);
+
+ Object resultObject = methodObject.invoke(instance, args);
+
+ return resultObject;
+ }
}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/SdkConfigUpdateUtil.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/SdkConfigUpdateUtil.java
index 029290f743b17c7799672f6e4fea2d41453c496b..177f4ca5d28dafc5e8144c3737092b356423ebba 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/SdkConfigUpdateUtil.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/SdkConfigUpdateUtil.java
@@ -1,13 +1,7 @@
package cn.com.mma.mobile.tracking.util;
-import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
import android.content.Context;
import android.net.ConnectivityManager;
import android.text.TextUtils;
@@ -18,208 +12,217 @@ import cn.com.mma.mobile.tracking.bean.SDK;
* config配置文件相关工具类
*/
public class SdkConfigUpdateUtil {
- private static SDK sdk = null;
- /**
- * 初始化Sdk配置文件
- */
- public static void initSdkConfigResult(final Context context,
- final String configUrl) {
- new Thread(new Runnable() {
- @Override
- public void run() {
- sdk = getNewestSDK(context, configUrl);
- if (sdk != null) {
- setSdk(sdk);
- }
- }
- }).start();
- }
+ private static SDK sdkConfig = null;
+ private static String configURL = null;
+ private static boolean isUpdating = false;
+
+
+ /**
+ * 在线更新SDKCOFIG配置
+ * @param context
+ * @param configUrl
+ */
+ public synchronized static void sync(final Context context, final String configUrl) {
+
+ if (isUpdating) return;
+
+ //如果达到更新周期且传入ConfigURL不为空,开启在线更新
+ if (!TextUtils.isEmpty(configUrl) && checkNeedUpdate(context)) {
+
+ configURL = configUrl;
+ isUpdating = true;
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+
+ try {
+ // natwork unavailable return
+ if (DeviceInfoUtil.isNetworkAvailable(context)) {
+ byte[] buffer = ConnectUtil.getInstance().performGet(configUrl);
+ if (buffer != null) {
+ sdkConfig = XmlUtil.doParser(new ByteArrayInputStream(buffer));
+ //如果可以成功解析为SDK实体类,并且存在Company配置,缓存原始XML数据
+ if (sdkConfig != null && sdkConfig.companies != null && sdkConfig.companies.size() > 0) {
+ String response = new String(buffer);
+ if (!TextUtils.isEmpty(response)) {
+ SharedPreferencedUtil.putString(context,
+ SharedPreferencedUtil.SP_NAME_CONFIG,
+ SharedPreferencedUtil.SP_CONFIG_KEY_FILE, response);
+
+ SharedPreferencedUtil.putLong(context,
+ SharedPreferencedUtil.SP_NAME_OTHER,
+ SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME,
+ System.currentTimeMillis());
+ Logger.d("Successful update sdkconfig files");
+ }
+ initOffLineCache(sdkConfig);
+ }
+ }
+
+ }
+
+ } catch (Exception e) {
+ Logger.w("Online update sdkconfig failed!:" + e.getMessage());
+ } finally {
+ isUpdating = false;
+ }
- /**
- * 获取最新的sdk文件
- */
- private static SDK getNewestSDK(Context context, String configUrl) {
- SDK sdkNewest;
- if (JudgeUpdateAccordingDate(context) && !TextUtils.isEmpty(configUrl)) {
- sdkNewest = dealUpdateConfig(context, configUrl);
- if (sdkNewest == null) {
- sdkNewest = getSDKFromPreferences(context);
- }
- } else {
- sdkNewest = getSDKFromPreferences(context);
- if (sdkNewest == null) {
- sdkNewest = dealUpdateConfig(context, configUrl);
- }
- }
- return sdkNewest;
- }
+ }
+ }).start();
+ }
- /**
- * 如果当前是 wifi 环境,每天更新一次配置文件,如果当前是 2G / 3G 环境,每隔 3 天更新一次配置文件
- */
- private static boolean JudgeUpdateAccordingDate(Context context) {
- boolean result = true;
- try {
- long currentTime = System.currentTimeMillis();
- long lastUpdateTime = SharedPreferencedUtil.getLong(context, SharedPreferencedUtil.SP_NAME_OTHER,
- SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME);
-
- if (currentTime < lastUpdateTime) {
- SharedPreferencedUtil.putLong(context, SharedPreferencedUtil.SP_NAME_OTHER,
- SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME, currentTime);
- return false;
- }
-
- // 每天更新一次:时间间隔大于1天则更新
- boolean isWifiUpdate = (CommonUtil.isConnected(context, ConnectivityManager.TYPE_WIFI)
- && (currentTime - lastUpdateTime >= Constant.TIME_ONE_DAY));
-
- // 每三天更新一次:时间间隔大于3天则更新
- boolean isMobileUpdate = (CommonUtil.isConnected(context, ConnectivityManager.TYPE_MOBILE)
- && (currentTime - lastUpdateTime >= Constant.TIME_THREE_DAY));
-
- if (isWifiUpdate || isMobileUpdate) {
- result = true;
- } else {
- result = false;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- //Logger.d("is need Update:" + result);
- return result;
- }
+ }
- /**
- * 网络更新config.xml文件后的
- *
- * @param configUrl
- */
- public static SDK dealUpdateConfig(Context context, String configUrl) {
- if (!DeviceInfoUtil.isNetworkAvailable(context)) {
- return null;
- }
- SDK sdk = null;
+ /**
+ * 检查是否要远程更新配置文件
+ * 当前 WIFI 环境,每天更新一次,2G/3G/4G 环境,每隔 3 天更新一次配置文件
+ * @param context
+ * @return
+ */
+ private static boolean checkNeedUpdate(Context context) {
+ boolean result = true;
try {
- byte[] buffer = ConnectUtil.getInstance().performGet(configUrl);
- if (buffer != null) {
- sdk = XmlUtil.doParser(new ByteArrayInputStream(buffer));
- if (sdk != null && sdk.companies != null && sdk.companies.size() > 0) {
- String response = new String(buffer);
- if (!TextUtils.isEmpty(response)) {
- SharedPreferencedUtil.putString(context,
- SharedPreferencedUtil.SP_NAME_CONFIG,
- SharedPreferencedUtil.SP_CONFIG_KEY_FILE, response);
-
- SharedPreferencedUtil.putLong(context,
- SharedPreferencedUtil.SP_NAME_OTHER,
- SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME,
- System.currentTimeMillis());
- Logger.d("mma_网络更新sdkconfig.xml成功");
- }
- }
+ long currentTime = System.currentTimeMillis();
+ long lastUpdateTime = SharedPreferencedUtil.getLong(context, SharedPreferencedUtil.SP_NAME_OTHER,
+ SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME);
+
+ if (currentTime < lastUpdateTime) {
+ SharedPreferencedUtil.putLong(context, SharedPreferencedUtil.SP_NAME_OTHER,
+ SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME, currentTime);
+ return false;
+ }
+
+ // 每天更新一次:时间间隔大于1天则更新
+ boolean isWifiUpdate = (CommonUtil.isConnected(context, ConnectivityManager.TYPE_WIFI)
+ && (currentTime - lastUpdateTime >= Constant.TIME_ONE_DAY));
+
+ // 每三天更新一次:时间间隔大于3天则更新
+ boolean isMobileUpdate = (CommonUtil.isConnected(context, ConnectivityManager.TYPE_MOBILE)
+ && (currentTime - lastUpdateTime >= Constant.TIME_THREE_DAY));
+
+ if (isWifiUpdate || isMobileUpdate) {
+ result = true;
+ } else {
+ result = false;
}
} catch (Exception e) {
e.printStackTrace();
}
- return sdk;
+ //Logger.d("is need Update:" + result);
+ return result;
}
+// /**
+// * 网络更新config.xml文件
+// *
+// * @param configUrl
+// */
+// private static SDK doUpdate(Context context, String configUrl) {
+// // natwork unavailable return
+// if (!DeviceInfoUtil.isNetworkAvailable(context)) {
+// return null;
+// }
+// SDK sdk = null;
+//
+// try {
+// byte[] buffer = ConnectUtil.getInstance().performGet(configUrl);
+// if (buffer != null) {
+// sdk = XmlUtil.doParser(new ByteArrayInputStream(buffer));
+// //如果可以成功解析为SDK实体类,并且存在Company配置,缓存原始XML数据
+// if (sdk != null && sdk.companies != null && sdk.companies.size() > 0) {
+// String response = new String(buffer);
+// if (!TextUtils.isEmpty(response)) {
+// SharedPreferencedUtil.putString(context,
+// SharedPreferencedUtil.SP_NAME_CONFIG,
+// SharedPreferencedUtil.SP_CONFIG_KEY_FILE, response);
+//
+// SharedPreferencedUtil.putLong(context,
+// SharedPreferencedUtil.SP_NAME_OTHER,
+// SharedPreferencedUtil.SP_OTHER_KEY_UPDATE_TIME,
+// System.currentTimeMillis());
+// Logger.d("Successful update sdk_config files");
+// }
+// }
+// }
+// } catch (Exception e) {
+// Logger.w("Online update sdk_config failed!:" + e.getMessage());
+// }
+//
+// return sdk;
+// }
+
/**
* 从SharedPreferences中获取sdkconfig.xml文件,转换成SDK对象
*/
- public static SDK getSDKFromPreferences(Context context) {
- try {
- String valueString = SharedPreferencedUtil.getString(context,
- SharedPreferencedUtil.SP_NAME_CONFIG,
- SharedPreferencedUtil.SP_CONFIG_KEY_FILE);
- InputStream is = null;
- try {
- if (valueString != null && valueString.length() > 0) {
- is = new ByteArrayInputStream(valueString.getBytes());
- } else {
- is = context.getAssets().open(XmlUtil.XMLFILE);
- }
- } catch (Exception e) {
- is = null;
- }
- return is != null ? XmlUtil.doParser(is) : null;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
+ private static SDK getSDKFromCache(Context context) {
+ try {
+ String cacheConfig = SharedPreferencedUtil.getString(context, SharedPreferencedUtil.SP_NAME_CONFIG, SharedPreferencedUtil.SP_CONFIG_KEY_FILE);
+ InputStream is = null;
+ SDK sdkcofig = null;
+ try {
+ //SP有缓存优先使用缓存
+ if (!TextUtils.isEmpty(cacheConfig)) {
+ is = new ByteArrayInputStream(cacheConfig.getBytes());
+ } else {//无缓存直接读取离线配置
+ is = context.getAssets().open(XmlUtil.XMLFILE);
+ }
+ if (is != null){
+ sdkcofig = XmlUtil.doParser(is);
+ initOffLineCache(sdkcofig);
+ }
+ } catch (Exception e) {
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ return sdkcofig;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
- /**
- * 网络请求sdkconfig.xml文件
- */
- private static String getConfigFromNetWork(String configUrl) {
- if (configUrl == null)
- return null;
- try {
- URL url = new URL(configUrl);
- HttpURLConnection urlConnection = (HttpURLConnection) url
- .openConnection();
- urlConnection.setConnectTimeout(10000);
- urlConnection.connect();
- InputStream inputStream = urlConnection.getInputStream();
- BufferedReader in = new BufferedReader(new InputStreamReader(
- inputStream));
- StringBuffer buffer = new StringBuffer();
- String line = "";
- while ((line = in.readLine()) != null) {
- buffer.append(line);
- }
- inputStream.close();
- return buffer.toString();
- } catch (MalformedURLException e) {
- e.printStackTrace();
- return null;
- } catch (IOException e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 设置SDK
- */
- private static void setSdk(SDK sdk) {
- //Logger.d("mma_setSdk");
- if (sdk != null) {
- try {
- if(sdk.offlineCache!=null){
- if (sdk.offlineCache.length != null
- && !"".equals(sdk.offlineCache.length))
- Constant.OFFLINECACHE_LENGTH = Integer
- .parseInt(sdk.offlineCache.length);
- if (sdk.offlineCache.queueExpirationSecs != null
- && !"".equals(sdk.offlineCache.queueExpirationSecs))
- Constant.OFFLINECACHE_QUEUEEXPIRATIONSECS = Integer
- .parseInt(sdk.offlineCache.queueExpirationSecs);
- if (sdk.offlineCache.timeout != null
- && !"".equals(sdk.offlineCache.timeout))
- Constant.OFFLINECACHE_TIMEOUT = Integer
- .parseInt(sdk.offlineCache.timeout);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- }
-
- public static SDK getSdk(final Context context) {
- if (sdk == null || sdk.companies == null) {
- //[子线程操作]没有获取配置文件成功,则使用app内置配置文件
- sdk = getSDKFromPreferences(context);
- setSdk(sdk);
+ /**
+ * 初始化缓存队列配置项:
+ * @param sdk
+ */
+ private static void initOffLineCache(SDK sdk) {
+ try {
+ if (sdk != null && sdk.offlineCache != null) {
+ if (!TextUtils.isEmpty(sdk.offlineCache.length))
+ Constant.OFFLINECACHE_LENGTH = Integer.parseInt(sdk.offlineCache.length);
+ if (!TextUtils.isEmpty(sdk.offlineCache.queueExpirationSecs))
+ Constant.OFFLINECACHE_QUEUEEXPIRATIONSECS = Integer.parseInt(sdk.offlineCache.queueExpirationSecs);
+ if (!TextUtils.isEmpty(sdk.offlineCache.timeout))
+ Constant.OFFLINECACHE_TIMEOUT = Integer.parseInt(sdk.offlineCache.timeout);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ /**
+ * 立即获取sdkconfig,如果因在线获取延迟,优先使用本地缓存配置数据
+ * @param context
+ * @return
+ */
+ public static SDK getSDKConfig(Context context) {
+ if (sdkConfig == null || sdkConfig.companies == null) {
+ //没有获取配置文件成功,则使用app内置配置文件
+ sdkConfig = getSDKFromCache(context);
+ //如果本地没有缓存,且有配远程更新地址,则立即在线获取
+ if (sdkConfig == null && !TextUtils.isEmpty(configURL)) {
+ sync(context, configURL);
+ }
}
- return sdk;
+ return sdkConfig;
}
}
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/DeviceMessage.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/DeviceMessage.java
index 5b6cf1828eea612dfd1eab42a027dce6e7138ee5..31a2b24ac1d022b49a106fa42865d2510c9825a3 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/DeviceMessage.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/DeviceMessage.java
@@ -43,9 +43,9 @@ public class DeviceMessage {
deviceMessage.put(JSON_MAC, CommonUtil.md5(mac));
- deviceMessage.put(JSON_IMEI, DeviceInfoUtil.getImei(context));
+ deviceMessage.put(JSON_IMEI, CommonUtil.md5(DeviceInfoUtil.getImei(context)));
- deviceMessage.put(JSON_ANDROIDID, DeviceInfoUtil.getAndroidId(context));
+ deviceMessage.put(JSON_ANDROIDID, CommonUtil.md5(DeviceInfoUtil.getAndroidId(context)));
deviceMessage.put(JSON_AKEY, DeviceInfoUtil.getPackageName(context));//AKEY=packagename
deviceMessage.put(JSON_ANAME, DeviceInfoUtil.getAppName(context));//ANAME=appname
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityJsService.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityJsService.java
index ca46e4eb047f34349263a3f527a9a140d8e097b0..8c742a9709945aed27c2777717156512775a62ed 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityJsService.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityJsService.java
@@ -20,7 +20,7 @@ public class ViewAbilityJsService {
private Context mContext;
- private SDK mSdkConfig;
+ //private SDK mSdkConfig;
private ScheduledExecutorService scheduledExecutorService = null;
private boolean isTaskStarted = false;
@@ -28,9 +28,9 @@ public class ViewAbilityJsService {
private HashMap viewabilityWorkers;
private static final int monitorInterval = 200;
- public ViewAbilityJsService(Context context, SDK sdk) {
+ public ViewAbilityJsService(Context context) {
mContext = context;
- mSdkConfig = sdk;
+ //mSdkConfig = sdk;
//KLog.init(true, "ViewAbilityJS");
viewabilityWorkers = new HashMap<>();
scheduledExecutorService = Executors.newScheduledThreadPool(1);
diff --git a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityMessage.java b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityMessage.java
index 6010a34d066a8be4f2fa5a8ba8d7d88afa9c532b..15f1de9590c5b71ae27e1996a9af08701d34dbd6 100644
--- a/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityMessage.java
+++ b/MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/viewability/webjs/ViewAbilityMessage.java
@@ -8,7 +8,6 @@ import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import org.json.JSONObject;
-
import cn.com.mma.mobile.tracking.viewability.common.ViewHelper;
/**
@@ -26,6 +25,7 @@ public class ViewAbilityMessage {
private static final String ADVIEWABILITY_SHOWFRAME = "AdviewabilityShowFrame";
private static final String ADVIEWABILITY_LIGHT = "AdviewabilityLight";
public static final String ADVIEWABILITY_TYPE = "AdviewabilityType";
+ private static final String ADVIEWABILITY_FORGROUND = "AdviewabilityForground";
public static JSONObject getViewAbilityEvents(Context context, View adView) {
@@ -76,8 +76,12 @@ public class ViewAbilityMessage {
visibleSize = visbleWidth + "x" + visbleHeight;
//覆盖率(被) 可视区域尺寸/视图原尺寸
- double temp = 1.0f - (visbleWidth * visbleHeight) * 1.0f / (width * height) * 1.0f;
- coverRate = (float) Math.round(temp * 100) / 100;
+ if (width * height == 0) {
+ coverRate = 1.0f;
+ } else {
+ double temp = 1.0f - (visbleWidth * visbleHeight) * 1.0f / (width * height) * 1.0f;
+ coverRate = (float) Math.round(temp * 100) / 100;
+ }
} catch (Exception e) {
e.printStackTrace();
@@ -85,6 +89,9 @@ public class ViewAbilityMessage {
int screenOn = ViewHelper.isScreenOn(adView) ? 1 : 0;
+ //是否前台运行 0=后台或遮挡 1=前台
+ int isForground = adView.hasWindowFocus() ? 1 : 0;
+
try {
jsonObject.put(ADVIEWABILITY_TIME, String.valueOf(System.currentTimeMillis()));
jsonObject.put(ADVIEWABILITY_FRAME, adSize);
@@ -94,6 +101,7 @@ public class ViewAbilityMessage {
jsonObject.put(ADVIEWABILITY_SHOWFRAME, visibleSize);
jsonObject.put(ADVIEWABILITY_COVERRATE, String.valueOf(coverRate));
jsonObject.put(ADVIEWABILITY_LIGHT, String.valueOf(screenOn));
+ jsonObject.put(ADVIEWABILITY_FORGROUND, String.valueOf(isForground));
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/README.md b/README.md
index 8b24b6d110ae3a54c99345664f8b365077cc211e..d0cbe8ed40dd70be17799cf3951b4d15cd9091ec 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,6 @@
-
```
@@ -194,10 +193,41 @@ public class MainActivity extends Activity {
####步骤4:验证和调试
SDK 的测试有两个方面:
- 1. 参数是否齐全,URL 拼接方式是否正确
- 2. 请求次数和第三方监测平台是否能对应上
+ 1. 参数是否齐全,URL 拼接方式是否正确
+ 2. 请求次数和第三方监测平台是否能对应上
-请联系第三方监测平台完成测试
+请联系第三方监测平台完成测试。
-# MMAViewabilitySDK_Android
+### 位置信息获取配置
+
+想要获取位置信息,需要如下两步:
+
+* 在AndroidManifest.xml 文件添加相关权限:
+
+```
+
+
+
+```
+
+* 监测代码对应的sdkconfig内Company标签的项设置为**true**。
+
+
+
+如果不想开启定位服务,需要**sdkconfig内将所有Company标签内的设置为false**。
+
+### 混淆配置
+
+如果APP使用了混淆技术,以防SDK被混淆报错,需要在混淆配置里添加如下代码:
+
+```
+# SDK开源,集成的Library(Jar)本身无混淆,二次混淆与否不影响
+#-keep class cn.com.mma.** { *; }
+#-keep class cn.mmachina.**{*;}
+#-dontwarn cn.com.mma.**
+#-dontwarn cn.mmachina.**
+# SDK用到了v4包里的API,请确保v4相关support包不被混淆
+#-keep class android.support.v4.** { *; }
+#-dontwarn android.support.v4.**
+```
diff --git "a/docs/\345\217\257\350\247\206\345\214\226\346\233\235\345\205\211\347\233\221\346\265\213\346\214\207\345\215\227/viewability_Android.md" "b/docs/\345\217\257\350\247\206\345\214\226\346\233\235\345\205\211\347\233\221\346\265\213\346\214\207\345\215\227/viewability_Android.md"
index cba1010e97b7b773ad410f341f6208682487a00e..51bc480354ae38a21131925ea8004330beb177c3 100644
--- "a/docs/\345\217\257\350\247\206\345\214\226\346\233\235\345\205\211\347\233\221\346\265\213\346\214\207\345\215\227/viewability_Android.md"
+++ "b/docs/\345\217\257\350\247\206\345\214\226\346\233\235\345\205\211\347\233\221\346\265\213\346\214\207\345\215\227/viewability_Android.md"
@@ -22,7 +22,6 @@
-
```
@@ -150,7 +149,42 @@ public class MainActivity extends Activity {
####步骤4:验证和调试
SDK 的测试有两个方面:
- 1. 参数是否齐全,URL 拼接方式是否正确
- 2. 请求次数和第三方监测平台是否能对应上
+ 1. 参数是否齐全,URL 拼接方式是否正确
+ 2. 请求次数和第三方监测平台是否能对应上
-请联系第三方监测平台完成测试
+请联系第三方监测平台完成测试。
+
+
+
+### 位置信息获取配置
+
+想要获取位置信息,需要如下两步:
+
+- 在AndroidManifest.xml 文件添加相关权限:
+
+```
+
+
+
+```
+
+- 监测代码对应的sdkconfig内Company标签的项设置为**true**。
+
+
+
+如果不想开启定位服务,需要**sdkconfig内将所有Company标签内的设置为false**。
+
+### 混淆配置
+
+如果APP使用了混淆技术,以防SDK被混淆报错,需要在混淆配置里添加如下代码:
+
+```
+# SDK开源,集成的Library(Jar)本身无混淆,二次混淆与否不影响
+#-keep class cn.com.mma.** { *; }
+#-keep class cn.mmachina.**{*;}
+#-dontwarn cn.com.mma.**
+#-dontwarn cn.mmachina.**
+# SDK用到了v4包里的API,请确保v4相关support包不被混淆
+#-keep class android.support.v4.** { *; }
+#-dontwarn android.support.v4.**
+```
\ No newline at end of file