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