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"
}
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 {
# 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 <fields>;
+}
+
+# 保留本地native方法不被混淆
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# 保留在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 <init>(android.content.Context);
+ public <init>(android.content.Context, android.util.AttributeSet);
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(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 <methods>;
+}
+
+-keep public interface com.ic.aidl.blood.IBloodRemoteService
+-keep public abstract interface com.ic.aidl.blood.IBloodRemoteService{
+public protected <methods>;
+}
+
+-keep public interface com.ic.aidl.ped.IPedAidlInterface
+-keep public abstract interface com.ic.aidl.ped.IPedAidlInterface{
+public protected <methods>;
+}
+
+-keep public interface com.ic.aidl.ped.IPedRemoteService
+-keep public abstract interface com.ic.aidl.ped.IPedRemoteService{
+public protected <methods>;
+}
+
+-keep public interface com.ic.aidl.weather.IWeatherAidlInterface
+-keep public abstract interface com.ic.aidl.weather.IWeatherAidlInterface{
+public protected <methods>;
+}
+
+-keep public interface com.ic.aidl.weather.IWeatherRemoteService
+-keep public abstract interface com.ic.weather.ped.IWeatherRemoteService{
+public protected <methods>;
+}
+
+# 保留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 <fields>;
+ !private <fields>;
+ !private <methods>;
+ 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 <methods>;
+}
+-keep enum org.greenrobot.eventbus.ThreadMode { *; }
+
+# And if you use AsyncExecutor:
+-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
+ <init>(java.lang.Throwable);
+}
\ No newline at end of file
android:name="com.amap.api.v2.apikey"
android:value="80c129088f7bbe251a846d645ee8360a" />
-
<service
android:name=".WorkService"
- android:process=":remote"
android:enabled="true"
- android:exported="true">
+ android:exported="true"
+ android:process=":remote">
<intent-filter>
<action android:name="com.ic.action.WORK_SERVICE" />
</intent-filter>
</activity>
<service android:name="com.amap.api.location.APSService" />
+
</application>
</manifest>
\ No newline at end of file
--- /dev/null
+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());
+ }
+}
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;
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;
@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:
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)
@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;
}
@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());
}
@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;
+ }
+ }
+ }
+ };
}
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;
IcLog.setLogHead("IcWorkService");
AndroidThreeTen.init(this);
+
+ CrashHandler crashHandler = CrashHandler.getInstance();
+ crashHandler.init(getApplicationContext());
}
public AppDatabase getDatabase() {
mRecordRun = new PedRecordRunnable(app.getRepository());
}
+ public void startPedRunGetCount(){
+ ThreadPoolManager.getInstance().execute(mPedRun);
+ }
+
public IBinder getPedBinder() {
return pedBinder;
}
@Override
public void queryPedCount() throws RemoteException {
- ThreadPoolManager.getInstance().execute(mPedRun);
+ startPedRunGetCount();
}
@Override
--- /dev/null
+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<String, String> infos = new HashMap<String, String>();
+ // 用于格式化日期,作为日志文件名的一部分
+ 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<String, String> 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;
+ }
+}
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) {
<resources>
<string name="app_name">IcWorkService</string>
+
+ <string name="program_abnormal">很抱歉,程序出现异常,即将退出</string>
</resources>
--- /dev/null
+#Mon Mar 23 18:58:17 CST 2020
+VERSION_CODE=11