From: kfl_614 Date: Mon, 23 Mar 2020 12:45:56 +0000 (+0800) Subject: 1.加入Crash,修改Binder方式,加入广播 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=231da9b42ba8335bd40036f0fc2f9044ebbc0610;p=icworkservice.git 1.加入Crash,修改Binder方式,加入广播 --- diff --git a/app/build.gradle b/app/build.gradle index 50ef5d6..b5fb414 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,23 @@ apply plugin: 'com.android.application' +static def getL02ApkBaseName() { + return "ICL02WorkService" +} + + android { + + def currentVersionCode = getVersionCode() + def currentVersionName = releaseTime() + compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { applicationId "com.ic.work" minSdkVersion 19 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode currentVersionCode + versionName "${currentVersionName}" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -57,6 +66,39 @@ android { signingConfig signingConfigs.key } } + + android.applicationVariants.all { variant -> + variant.outputs.all { + if (variant.buildType.name == "release") { + outputFileName = "${getL02ApkBaseName()}_V${currentVersionCode}_${currentVersionName}_release.apk" + } else { + outputFileName = "${getL02ApkBaseName()}_V${currentVersionCode}_${currentVersionName}_debug.apk" + } + } + } +} + +def getVersionCode() { + def versionCodeFile = file('version_code.properties') + if (versionCodeFile.canRead()) { + Properties properties = new Properties() + properties.load(new FileInputStream(versionCodeFile)) + def versionCode = properties['VERSION_CODE'].toInteger()//读取version_code.properties文件存放的版本号。 + def runTasks = gradle.startParameter.taskNames + def task = ':app:assembleRelease' + if (task in runTasks) { + properties['VERSION_CODE'] = (++versionCode).toString() + properties.store(versionCodeFile.newWriter(), null) + } + + return versionCode + } else { + throw new GradleException("无法读取version_code.properties文件!") + } +} + +def releaseTime() { + return new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("GMT+08:00")) } dependencies { diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f1b4245..9ff9d79 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -19,3 +19,147 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile +-dontoptimize # 混合时不使用大小写混合,混合后的类名为小写 +-dontusemixedcaseclassnames # 混合时不使用大小写混合,混合后的类名为小写 +-dontskipnonpubliclibraryclasses # 不跳过library中的非public的类 +-dontskipnonpubliclibraryclassmembers # 不跳过library中的非public的类成员 +-dontpreverify # 不做预校验,preverify是proguard的四个步骤之一,Android平台不需要preverify,去掉这一步能够加快混淆速度 +-verbose # 在处理时打印冗长的信息 + +# 保留异常表,以便编译器知道哪些异常可能被抛出 +# 保留InnerClasses,否则外部无法引用内部类 +# 保留Signature,否则无法访问泛型 +-keepattributes Exceptions,SourceFile,LineNumberTable,EnclosingMethod,Signature,*Annotation*,InnerClasses,Deprecated + +################################## 需要保留的公共部分 ################################## +# 保留四大组件,自定义的Application等等这些类不被混淆 +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class * extends android.view.View +-keep public class com.android.vending.licensing.ILicensingService + +-keep class android.support.** { *; } +-keep public class * extends android.support.v4.** +-keep public class * extends android.support.v7.** +-keep public class * extends android.support.annotation.** +-keep public class * extends android.app.Fragment +-keep class com.google.** { *; } + +# 保留R下面的资源 +-keep class **.R$* {*;} +-keepclassmembers class **.R$* { + public static ; +} + +# 保留本地native方法不被混淆 +-keepclasseswithmembernames class * { + native ; +} + +# 保留在Activity中的方法参数是view的方法, +# 这样以来我们在layout中写的onClick就不会被影响 +-keepclassmembers class * extends android.app.Activity{ + public void *(android.view.View); +} + +# 保留我们自定义控件(继承自View)不被混淆 +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# 保留枚举类不被混淆 +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +-keep public interface com.ic.aidl.blood.IBloodAidlInterface +-keep public abstract interface com.ic.aidl.blood.IBloodAidlInterface{ +public protected ; +} + +-keep public interface com.ic.aidl.blood.IBloodRemoteService +-keep public abstract interface com.ic.aidl.blood.IBloodRemoteService{ +public protected ; +} + +-keep public interface com.ic.aidl.ped.IPedAidlInterface +-keep public abstract interface com.ic.aidl.ped.IPedAidlInterface{ +public protected ; +} + +-keep public interface com.ic.aidl.ped.IPedRemoteService +-keep public abstract interface com.ic.aidl.ped.IPedRemoteService{ +public protected ; +} + +-keep public interface com.ic.aidl.weather.IWeatherAidlInterface +-keep public abstract interface com.ic.aidl.weather.IWeatherAidlInterface{ +public protected ; +} + +-keep public interface com.ic.aidl.weather.IWeatherRemoteService +-keep public abstract interface com.ic.weather.ped.IWeatherRemoteService{ +public protected ; +} + +# 保留Parcelable序列化类不被混淆 +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +# 保留Serializable序列化的类不被混淆 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + !private ; + !private ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + +# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆 +-keepclassmembers class * { + void *(**On*Event); + void *(**On*Listener); +} + + +-keep class com.sun.jna.** { *; } +-dontwarn com.sun.jna.** + +-keep public class com.android.support.a +-keep public class com.android.support.b +-keep public class rx.internal.util + +#event bus +-keepattributes *Annotation* +-keepclassmembers class * { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } + +# And if you use AsyncExecutor: +-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { + (java.lang.Throwable); +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c017541..53673ad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -39,12 +39,11 @@ android:name="com.amap.api.v2.apikey" android:value="80c129088f7bbe251a846d645ee8360a" /> - + android:exported="true" + android:process=":remote"> @@ -60,6 +59,7 @@ + \ No newline at end of file diff --git a/app/src/main/java/com/ic/work/BootBroadcastReceiver.java b/app/src/main/java/com/ic/work/BootBroadcastReceiver.java new file mode 100644 index 0000000..ad136df --- /dev/null +++ b/app/src/main/java/com/ic/work/BootBroadcastReceiver.java @@ -0,0 +1,16 @@ +package com.ic.work; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import com.ic.work.utils.ServiceUtil; + +public class BootBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + ServiceUtil.startServiceUtil(context.getApplicationContext(), + "com.ic.action.WORK_SERVICE", + context.getPackageName()); + } +} diff --git a/app/src/main/java/com/ic/work/WorkService.java b/app/src/main/java/com/ic/work/WorkService.java index 1a1fdb4..dd9e582 100644 --- a/app/src/main/java/com/ic/work/WorkService.java +++ b/app/src/main/java/com/ic/work/WorkService.java @@ -1,8 +1,12 @@ package com.ic.work; import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.IBinder; +import android.text.TextUtils; import com.ic.work.event.BloodCheckResultEvent; import com.ic.work.event.BloodCheckTipsEvent; @@ -27,6 +31,11 @@ public class WorkService extends Service { private static final String TAG = "WorkService"; + private static final String HEART_ACTION = "com.ic.action.BLOOD_HEART"; + private static final String PED_ACTION = "com.ic.action.PED_COUNT"; + + private static final String GET_PED_ACTION = "com.ic.action.GET_PED_COUNT"; + private WeatherProcess weatherProcess; private BloodProcess bloodProcess; private PedProcess pedProcess; @@ -38,16 +47,15 @@ public class WorkService extends Service { @Override public IBinder onBind(Intent intent) { if (intent != null) { - int reqType = intent.getIntExtra("REQ_TYPE", -1); - IcLog.i(TAG,"Bind reqType"+reqType); - switch (reqType) { - case 101: + IcLog.i(TAG,intent.getPackage()); + switch (intent.getPackage()) { + case "com.ic.weather": //天气 return weatherProcess.getWeatherBinder(); - case 102: + case "com.ic.blood": //血压 return bloodProcess.getBloodBinder(); - case 103: + case "com.ic.hardware": //计步 return pedProcess.getPedBinder(); default: @@ -76,28 +84,32 @@ public class WorkService extends Service { mWeatherHelper.startLocation(getApplicationContext()); + registerBroadcast(); + IcLog.i(TAG, "work service is start"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { - IcLog.i(TAG,"WorkService onStartCommand"); + IcLog.i(TAG, "WorkService onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); - IcLog.i(TAG,"WorkService onDestroy"); + IcLog.i(TAG, "WorkService onDestroy"); bloodProcess = null; mApp = null; EventBus.getDefault().unregister(this); + + unregisterReceiver(mIntentReceiver); } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(LocationResultEvent event) { - mWeatherHelper.queryWeatherServerInfo(mApp.getWeatherRepository(),event.getmCity()); + mWeatherHelper.queryWeatherServerInfo(mApp.getWeatherRepository(), event.getmCity()); } @Subscribe(threadMode = ThreadMode.MAIN) @@ -122,19 +134,19 @@ public class WorkService extends Service { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PedSettingEvent event) { - if(pedProcess != null){ + if (pedProcess != null) { return; } - switch (event.getType()){ + switch (event.getType()) { case 1: int height = event.getValue(); - SPUtils.setPedHeightSP(getApplicationContext(),height); + SPUtils.setPedHeightSP(getApplicationContext(), height); pedProcess.updateHeight(height); break; case 2: int weight = event.getValue(); - SPUtils.setPedWighttSP(getApplicationContext(),weight); + SPUtils.setPedWighttSP(getApplicationContext(), weight); pedProcess.updateWeight(weight); break; } @@ -142,14 +154,14 @@ public class WorkService extends Service { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PedRecordResultEvent event) { - if(pedProcess != null){ + if (pedProcess != null) { pedProcess.sendPedRecord(event.getRecordList()); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(PedCountEvent event) { - if(pedProcess != null){ + if (pedProcess != null) { pedProcess.sendPedCount(event.getPedCount()); } @@ -159,29 +171,52 @@ public class WorkService extends Service { @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(WeatherResultEvent event) { - if(weatherProcess != null){ + if (weatherProcess != null) { weatherProcess.sendCurrWeather(event.getParcelable()); } } + @Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(WeatherAgainEvent event) { - if(mWeatherHelper != null){ + if (mWeatherHelper != null) { mWeatherHelper.startLocation(getApplicationContext()); } } - private void sendPedCountBroadcast(int count){ + public void registerBroadcast() { + IntentFilter filter = new IntentFilter(); + filter.addAction(GET_PED_ACTION); + registerReceiver(mIntentReceiver, filter); + } + + private void sendPedCountBroadcast(int count) { Intent pedIntent = new Intent(); - pedIntent.setAction("com.ic.action.PED_COUNT"); - pedIntent.putExtra("PED_COUNT",count); + pedIntent.setAction(PED_ACTION); + pedIntent.putExtra("PED_COUNT", count); sendBroadcast(pedIntent); } - private void sendHeartBroadcast(int count){ + private void sendHeartBroadcast(int count) { Intent pedIntent = new Intent(); - pedIntent.setAction("com.ic.action.BLOOD_HEART"); - pedIntent.putExtra("BLOOD_HEART",count); + pedIntent.setAction(HEART_ACTION); + pedIntent.putExtra("BLOOD_HEART", count); sendBroadcast(pedIntent); } + private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null) { + String acyion = intent.getAction(); + if (TextUtils.isEmpty(acyion)) { + return; + } + switch (acyion) { + case GET_PED_ACTION: + pedProcess.startPedRunGetCount(); + break; + } + } + } + }; } diff --git a/app/src/main/java/com/ic/work/WorkServiceApp.java b/app/src/main/java/com/ic/work/WorkServiceApp.java index 2c9af47..9930cf9 100644 --- a/app/src/main/java/com/ic/work/WorkServiceApp.java +++ b/app/src/main/java/com/ic/work/WorkServiceApp.java @@ -5,6 +5,7 @@ import android.app.Application; import com.ic.work.db.AppDatabase; import com.ic.work.db.PedInjection; import com.ic.work.db.WeatherInjection; +import com.ic.work.utils.CrashHandler; import com.ic.work.utils.IcLog; import com.jakewharton.threetenabp.AndroidThreeTen; @@ -16,6 +17,9 @@ public class WorkServiceApp extends Application { IcLog.setLogHead("IcWorkService"); AndroidThreeTen.init(this); + + CrashHandler crashHandler = CrashHandler.getInstance(); + crashHandler.init(getApplicationContext()); } public AppDatabase getDatabase() { diff --git a/app/src/main/java/com/ic/work/process/PedProcess.java b/app/src/main/java/com/ic/work/process/PedProcess.java index 6c3f817..77738b2 100644 --- a/app/src/main/java/com/ic/work/process/PedProcess.java +++ b/app/src/main/java/com/ic/work/process/PedProcess.java @@ -32,6 +32,10 @@ public class PedProcess { mRecordRun = new PedRecordRunnable(app.getRepository()); } + public void startPedRunGetCount(){ + ThreadPoolManager.getInstance().execute(mPedRun); + } + public IBinder getPedBinder() { return pedBinder; } @@ -53,7 +57,7 @@ public class PedProcess { @Override public void queryPedCount() throws RemoteException { - ThreadPoolManager.getInstance().execute(mPedRun); + startPedRunGetCount(); } @Override diff --git a/app/src/main/java/com/ic/work/utils/CrashHandler.java b/app/src/main/java/com/ic/work/utils/CrashHandler.java new file mode 100644 index 0000000..8a779b6 --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/CrashHandler.java @@ -0,0 +1,213 @@ +package com.ic.work.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import com.ic.work.R; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Created by Administrator on 2017/5/18. + */ + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + public static final String TAG = CrashHandler.class.getName(); + + // 系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + // CrashHandler实例 + private static CrashHandler INSTANCE = new CrashHandler(); + // 程序的Context对象 + private Context mContext; + // 用来存储设备信息和异常信息 + private Map infos = new HashMap(); + // 用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS", Locale.getDefault()); + private DateFormat dateFormatDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + + /** + * 保证只有一个CrashHandler实例 + */ + private CrashHandler() { + } + + /** + * 获取CrashHandler实例 ,单例模式 + */ + public static CrashHandler getInstance() { + return INSTANCE; + } + + /** + * 初始化 + * + * @param context + */ + public void init(Context context) { + mContext = context; + // 获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + // 如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { +// Log.e(TAG, "error : " + e); + e.printStackTrace(); + } + } + + // 退出程序 + ex.printStackTrace(); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + // 使用Toast来显示异常信息 + new Thread() { + @Override + public void run() { + Looper.prepare(); + if (mContext != null) { + Toast.makeText(mContext, R.string.program_abnormal, Toast.LENGTH_LONG) + .show(); + Looper.loop(); + } + } + }.start(); + // 收集设备参数信息 + collectDeviceInfo(mContext); + // 保存日志文件 + saveCrashInfo2File(ex); + return true; + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + infos.clear(); + infos.put("===", " PackageInfo ==="); + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); + + if (pi != null) { + String versionName = pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info " + e); + } + + infos.put("===", " Build ==="); + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + ":" + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info," + e); + } + } + } + + /** + * 保存错误信息到文件中 + * + * @param ex + * @return 返回文件名称, 便于将文件传送到服务器 + */ + private String saveCrashInfo2File(Throwable ex) { + + String time = formatter.format(new Date()); + StringBuilder sb = new StringBuilder(); + sb.append("=== ").append(time).append(" ===\n"); + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); +// ex.printStackTrace(); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); +// cause.printStackTrace(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + sb.append("\n"); + + sb.append("--- DEVICE INFO ---\n"); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key).append("=").append(value).append("\n"); + } + sb.append("\n\n"); + + try { + String fileName = "IcWorkService-" + dateFormatDate.format(new Date()) + ".log"; + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + File dir = new File(Environment.getExternalStorageDirectory().getPath(), "Android/ic/crash/IcWorkService"); + String path = dir.getPath(); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(new File(path, fileName), true); + fos.write(sb.toString().getBytes()); + fos.close(); + } + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...," + e); + } + return null; + } +} diff --git a/app/src/main/java/com/ic/work/utils/IcLog.java b/app/src/main/java/com/ic/work/utils/IcLog.java index a7bb72c..ce8d0b9 100644 --- a/app/src/main/java/com/ic/work/utils/IcLog.java +++ b/app/src/main/java/com/ic/work/utils/IcLog.java @@ -12,7 +12,7 @@ import com.ic.work.BuildConfig; public class IcLog { private static final String DOT = "."; - private static boolean isDebug = BuildConfig.DEBUG; + private static boolean isDebug = true; private static String tagHead = ""; public static void v(String tag, String msg) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 95308ff..00b1727 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ IcWorkService + + 很抱歉,程序出现异常,即将退出 diff --git a/app/version_code.properties b/app/version_code.properties new file mode 100644 index 0000000..f9789d8 --- /dev/null +++ b/app/version_code.properties @@ -0,0 +1,2 @@ +#Mon Mar 23 18:58:17 CST 2020 +VERSION_CODE=11