From eabebbc094a80f6dea030c2622f1026f989dd958 Mon Sep 17 00:00:00 2001 From: yangxiaolong Date: Mon, 12 Mar 2018 20:37:38 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=B7=BB=E5=8A=A0=E5=AE=9A=E4=BD=8D=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=E8=8E=B7=E5=8F=96=E5=8A=9F=E8=83=BD=202.=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E6=9B=B4=E6=96=B0=E5=8F=AF=E8=A7=86=E5=8C=96JS?= =?UTF-8?q?=E7=9B=91=E6=B5=8B=E8=8E=B7=E5=8F=96=E5=B1=9E=E6=80=A7=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=203.=E4=BF=AE=E5=A4=8D=E5=9C=A8=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=97=A7=E9=80=9A=E7=94=A8=E7=89=88SDK=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=97=B6=E5=9B=A0=E7=BC=BA=E5=A4=B1ViewAbili?= =?UTF-8?q?ty=E9=83=A8=E5=88=86=E5=AF=BC=E8=87=B4=E6=99=AE=E9=80=9A?= =?UTF-8?q?=E7=9B=91=E6=B5=8B=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=204.=E4=BC=98=E5=8C=96sdkconfig=E6=9B=B4=E6=96=B0=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E7=B1=BB=205.=E6=9B=B4=E6=96=B0=E5=BC=80=E5=8F=91?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/AndroidManifest.xml | 6 +- .../com/mma/mobile/tracking/api/Constant.java | 2 +- .../com/mma/mobile/tracking/api/Countly.java | 65 ++- .../tracking/api/RecordEventMessage.java | 12 +- .../tracking/api/SendMessageThread.java | 8 +- .../tracking/api/ViewAbilityHandler.java | 15 +- .../mobile/tracking/util/AppListUploader.java | 21 +- .../tracking/util/LocationCollector.java | 225 +++++++++++ .../mobile/tracking/util/LocationUtil.java | 97 ----- .../com/mma/mobile/tracking/util/Logger.java | 5 + .../mma/mobile/tracking/util/Reflection.java | 286 +++++++------ .../tracking/util/SdkConfigUpdateUtil.java | 381 +++++++++--------- .../viewability/webjs/DeviceMessage.java | 4 +- .../webjs/ViewAbilityJsService.java | 6 +- .../viewability/webjs/ViewAbilityMessage.java | 14 +- README.md | 40 +- .../viewability_Android.md" | 42 +- 17 files changed, 762 insertions(+), 467 deletions(-) create mode 100644 MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationCollector.java delete mode 100644 MobileTracking/libmobiletracking/src/main/java/cn/com/mma/mobile/tracking/util/LocationUtil.java diff --git a/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml b/MobileTracking/MobileTrackingDemo/src/main/AndroidManifest.xml index ccba7b4..876067d 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 8a8666c..baafb1f 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 0000000..97f5c10 --- /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 afec3a4..0000000 --- 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 6e55152..9d3e63e 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 21f30a4..d772367 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 029290f..177f4ca 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 5b6cf18..31a2b24 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 ca46e4e..8c742a9 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 6010a34..15f1de9 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 8b24b6d..d0cbe8e 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 cba1010..51bc480 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 -- Gitee