美文网首页iOS && Androidandroid开源APPAndroid
开发一个优秀的Android应用你必须要加入的代码及配置

开发一个优秀的Android应用你必须要加入的代码及配置

作者: alexis_zyp | 来源:发表于2017-06-15 18:06 被阅读2232次

    1 . 开发一个Android App我们一般需要继承Application来初始化一些配置,如下所示:

    a. Application中有一个registerActivityLifecycleCallbacks()方法,可以在回调中把整个应用打开的Activity保存在集合中、销毁的Activity重集合中删除。个人觉得这种方式比BaseActivity的方式或者每打开一个Activity把当前的引用加入到集合中的方式优雅多了,推荐大家用这种方式。关闭应用也非常方便,遍历保存Activity的集合,�执行finish()就好。

    /**
     * 注册ActivityListener
     */
    private void registerActivityListener() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    if (null == mActivitys) {
                        return;
                    }
                    mActivitys.add(activity);
                }
                @Override
                public void onActivityStarted(Activity activity) {}
                @Override
                public void onActivityResumed(Activity activity) {}
                @Override
                public void onActivityPaused(Activity activity) {}
                @Override
                public void onActivityStopped(Activity activity) {}
                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
                @Override
                public void onActivityDestroyed(Activity activity) {
                    if (null == activity && mActivitys.isEmpty()) {
                        return;
                    }
                    if (mActivitys.contains(activity)) {
                        mActivitys.remove(activity);
                    }
                }
            });
        }
    }
    

    b. 严苛模式StrictMode:建议大家在Debug版本打开严苛模式。 例如:严苛模式下可以检测到你应用中没有关闭的流,可以减少OOM,如下所示,可以看到在在控制台严苛模式模式下的Log输出。

    image.png

    ThreadPolicy线程策略检测
    自定义的耗时调用 使用detectCustomSlowCalls()开启
    磁盘读取操作 使用detectDiskReads()开启
    磁盘写入操作 使用detectDiskWrites()开启
    网络操作 使用detectNetwork()开启

    VmPolicy虚拟机策略检测
    Activity泄露 使用detectActivityLeaks()开启
    未关闭的Closable对象泄露 使用detectLeakedClosableObjects()开启
    泄露的Sqlite对象 使用detectLeakedSqlLiteObjects()开启
    检测实例数量 使用setClassInstanceLimit()开启

    /**严苛模式主要检测两大问题,一个是线程策略,即TreadPolicy,另一个是VM策略,即VmPolicy。*/
    if (AppConfig.IS_DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
    }
    

    c .在onCreate中,检测当前进程名称是否为应用包名,否则return (像百度地图等sdk需要在单独的进程中执行,会多次执行Application的onCreate()方法,所以为了只初始化一次应用配置,作此判断),代码如下:

     /**检测当前进程名称是否为应用包名,否则return (像百度地图等sdk需要在单独的进程中执行,会多次执行Application的onCreate()方法,所以为了只初始化一次应用配置,作此判断)*/
    if (!CommonUtil.getCurProcessName(this).equals(getPackageName())) {
      return;
    }
    

    d . �Crash全局异常捕获,用到了一个第三方库,使用方法如下:

    compile 'cat.ereza:customactivityoncrash:1.5.0'
    
    CustomActivityOnCrash.install(this);
    

    应用发生异常时customactivityoncrash库�会打开一个如下图所示的Activity页面,可以查看错误。


    image.png

    e .其他配置初始化

     private void init() {
    
        /**注册ActivityListener*/
        registerActivityListener();
    
        /**crash异常捕获*/
        if (AppConfig.IS_DEBUG) {
            CustomActivityOnCrash.install(this);
        }
    
        /**初始化base url*/
        if (AppConfig.IS_DEBUG) {
            final String base_url = SPUtils.getString(SPUtils.DEFAULT_FILE_NAME, SharePrefsConstant.SP_BASE_URL, "");
            if (TextUtils.isEmpty(base_url)) return;
            AppConfig.updateAllUrl(base_url);
        }
    
        /**初始化LeakCanary */
        if (AppConfig.IS_DEBUG) {
            if (LeakCanary.isInAnalyzerProcess(this)) {
                return;
            }
            LeakCanary.install(this);
        }
    }
    

    2 .�完整MyApplication代码,如下所示:

    public class MyApplication extends Application {
    
        private static MyApplication application;
    
        /**
         * 维护Activity的List
         */
        private static List<Activity> mActivitys = Collections.synchronizedList(new LinkedList<Activity>());
    
    
        @Override
        public void onCreate() {
            /**严苛模式主要检测两大问题,一个是线程策略,即TreadPolicy,另一个是VM策略,即VmPolicy。*/
            if (AppConfig.IS_DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
                StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
            }
            super.onCreate();
    
            application = this;
    
            /**检测当前进程名称是否为应用包名,否则return (像百度地图等sdk需要在单独的进程中执行,会多次执行Application的onCreate()方法,所以为了只初始化一次应用配置,作此判断)*/
            if (!CommonUtil.getCurProcessName(this).equals(getPackageName())) {
                return;
            }
    
            /**初始化一些应用配置*/
            init();
        }
    
        private void init() {
    
            /**注册ActivityListener*/
            registerActivityListener();
    
            /**crash异常捕获*/
            if (AppConfig.IS_DEBUG) {
                CustomActivityOnCrash.install(this);
            }
    
            /**初始化base url*/
            if (AppConfig.IS_DEBUG) {
                final String base_url = SPUtils.getString(SPUtils.DEFAULT_FILE_NAME, SharePrefsConstant.SP_BASE_URL, "");
                if (TextUtils.isEmpty(base_url)) return;
                AppConfig.updateAllUrl(base_url);
            }
    
            /**初始化LeakCanary */
            if (AppConfig.IS_DEBUG) {
                if (LeakCanary.isInAnalyzerProcess(this)) {
                    return;
                }
                LeakCanary.install(this);
            }
        }
    
        public static MyApplication getApplication() {
            return application;
        }
    
    
        public static void finishAllActivity() {
            if (mActivitys == null || mActivitys.isEmpty()) {
                return;
            }
            for (Activity activity : mActivitys) {
                activity.finish();
            }
        }
    
    
        /**
         * 获取当前Activity(栈中最后一个压入得)
         */
        public static Activity getCurrentActivity() {
            if (mActivitys == null || mActivitys.isEmpty()) {
                return null;
            }
            Activity activity = mActivitys.get(mActivitys.size() - 1);
            return activity;
        }
    
        /**
         * 注册ActivityListener
         */
        private void registerActivityListener() {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                        if (null == mActivitys) {
                            return;
                        }
                        mActivitys.add(activity);
                    }
                    @Override
                    public void onActivityStarted(Activity activity) {}
                    @Override
                    public void onActivityResumed(Activity activity) {}
                    @Override
                    public void onActivityPaused(Activity activity) {}
                    @Override
                    public void onActivityStopped(Activity activity) {}
                    @Override
                    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
                    @Override
                    public void onActivityDestroyed(Activity activity) {
                        if (null == activity && mActivitys.isEmpty()) {
                            return;
                        }
                        if (mActivitys.contains(activity)) {
                            mActivitys.remove(activity);
                        }
                    }
                });
            }
        }
    }
    

    3 . 应用的入口SplashActivity的onCreate方法中要加入如下代码,解决首次安装应用,点击应用图标打开应用,点击home健回到桌面,再次点击应用图标,进入应用时多次初始化SplashActivity的问题

    /**在应用的入口activity加入以下代码,解决首次安装应用,点击应用图标打开应用,点击home健回到桌面,再次点击应用图标,进入应用时多次初始化SplashActivity的问题*/
    if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
        finish();
        return;
    }
    if (!isTaskRoot()) {
        finish();
        return;
    }
    

    4 . �app下的build.gradle配置,代码如下

    apply plugin: 'com.android.application'
    apply plugin: 'com.antfortune.freeline'
    
    android {
        //国内镜像地址来下载  $ ./gradlew initFreeline -Pmirror
        freeline {
            hack true
            productFlavor 'zyp'
        }
    
        compileSdkVersion rootProject.ext.compileSdkVersion
        buildToolsVersion rootProject.ext.buildToolsVersion
        defaultConfig {
            applicationId "com.zyp"
            minSdkVersion rootProject.ext.minSdkVersion
            targetSdkVersion rootProject.ext.targetSdkVersion
            versionCode rootProject.ext.versionCode
            versionName rootProject.ext.versionName
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
            vectorDrawables.useSupportLibrary = true
        }
    
        signingConfigs {
            debug {
                storeFile file("debug.keystore")
            }
            release {
                storeFile file("release.keystore")
    //            storeFile file("release.jks")
                keyAlias 'androiddebugkey'
                storePassword 'android'
                keyPassword 'android'
            }
        }
    
        buildTypes {
            debug {
                applicationIdSuffix ".debug"
                manifestPlaceholders = [app_label: "@string/app_name_debug"]
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zyp"]
                manifestPlaceholders = [BAIDU_API_KEY_VALUE: "CC939499621bc8191c63799999b1f987", UMENG_APPKEY_VALUE: "4ef289045270156bd6999998"]
    
                buildConfigField "String", "BASE_URL", "\"https://api.test\""
                buildConfigField "String[]", "BASE_TEST_URL", "{\"https://api.test\", \"https://api.test1\", \"https://api.test2\", \"https://api.test3\", \"https://api.test4\"}"
                buildConfigField "boolean", "IS_LOG", "true"
                buildConfigField "boolean", "IS_DEBUG", "true"
    
                debuggable true
                zipAlignEnabled false
                shrinkResources false
                minifyEnabled false
                signingConfig signingConfigs.debug
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
    
            release {
                manifestPlaceholders = [app_label: "@string/app_name"]
                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "zyp"]
                manifestPlaceholders = [BAIDU_API_KEY_VALUE: "CC939499621bc8191c63799999b1f987", UMENG_APPKEY_VALUE: "4ef289045270156bd6999998"]
    
                buildConfigField "String", "BASE_URL", "\"https://api.release\""
                buildConfigField "String[]", "BASE_TEST_URL", "{\"https://api.release1\", \"https://api.release2\"}"
                buildConfigField "boolean", "IS_LOG", "false"
                buildConfigField "boolean", "IS_DEBUG", "false"
    
    
                debuggable false
                zipAlignEnabled true
                shrinkResources true
                minifyEnabled true
                signingConfig signingConfigs.release
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    
        applicationVariants.all { variant ->
            variant.outputs.each { output ->
                def outputFile = output.outputFile
                def fileName
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    // 输出apk名称为zyp_v1.0.0_wandoujia.apk
                    if (variant.buildType.name.equals('release')) {
                        fileName = "zyp_v${defaultConfig.versionName}_${variant.productFlavors[0].name}_release.apk"
                    } else if (variant.buildType.name.equals('debug')) {
                        fileName = "zyp_v${defaultConfig.versionName}_${variant.productFlavors[0].name}_debug.apk"
                    }
                    output.outputFile = new File(outputFile.parent, fileName)
                }
            }
        }
    
        // 友盟多渠道打包
        productFlavors {
            zyp {}
            //      _360yingyong {}
            //      yingyongbao {}
            //      baidushouzhu {}
            //      xiaomi {}
            //      wandoujia {}
            //      anzhi {}
            //      jifeng {}
            //      liantongwo {}
            //      yidongmm {}
            //      huawei {}
            //      lianxiang {}
            //      meizu {}
            //      oppo {}
            //      leshi {}
            //      mumayi {}
            //      nduowang {}
            //      wangyi {}
            //      sinaweibo {}
            //      sougoushouzhu {}
            //      google {}
            //      samsung {}
            //      vivo{}
        }
    
        productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    
        }
    
        dexOptions {
            preDexLibraries = false
            jumboMode = false
            javaMaxHeapSize "4g"
        }
    
        lintOptions {
            checkReleaseBuilds false
            abortOnError false
        }
        packagingOptions {
            exclude 'META-INF/LICENSE.txt'
            exclude 'LICENSE.txt'
            exclude 'META-INF/NOTICE.txt'
            exclude 'META-INF/DEPENDENCIES.txt'
            exclude 'META-INF/LICENSE.txt'
            exclude 'META-INF/NOTICE'
            exclude 'META-INF/LICENSE'
            exclude 'META-INF/DEPENDENCIES'
            exclude 'META-INF/notice.txt'
            exclude 'META-INF/license.txt'
            exclude 'META-INF/dependencies.txt'
            exclude 'META-INF/LGPL2.1'
            exclude 'META-INF/rxjava.properties'
        }
    
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_7
            targetCompatibility JavaVersion.VERSION_1_7
        }
    
        sourceSets.main {
    //        jniLibs.srcDirs = ['libs/jniLibs']
        }
    
    
    }
    
    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        androidTestCompile("com.android.support.test.espresso:espresso-core:${espressoCore}", {
            exclude group: 'com.android.support', module: 'support-annotations'
        })
        testCompile "junit:junit:${junit}"
    
        compile "com.android.support:appcompat-v7:${appcompatV7}"
        compile "com.android.support.constraint:constraint-layout:${constraintLayout}"
        compile "com.android.support:design:${design}"
        compile "com.android.support:support-vector-drawable:${supportVectorDrawable}"
    
        compile "cat.ereza:customactivityoncrash:${customactivityoncrash}"
    
        debugCompile "com.squareup.leakcanary:leakcanary-android:${leakcanaryVersion}"
        releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakcanaryVersion}"
        testCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakcanaryVersion}"
      
    }
    
    

    5 . 应用根目录下得build.gradle文件配置,代码如下:

    // Top-level build file where you can add configuration options common to all sub-projects/modules.
    
    ext {
        compileSdkVersion = 25
        buildToolsVersion = "25.0.3"
        minSdkVersion = 15
        targetSdkVersion = 22
        versionCode = 1
        versionName = "1.0.0"
    
        espressoCore = "2.2.2"
        junit = "4.12"
        constraintLayout = "1.0.2"
        customactivityoncrash = "1.5.0"
        leakcanaryVersion = "1.5.1"
        appcompatV7 = "25.3.1"
        design = "25.3.1"
        supportVectorDrawable = "25.3.1"
    
    }
    
    buildscript {
        repositories {
            jcenter()
            mavenCentral()
            maven { url 'https://jitpack.io' }
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.3.0'
            classpath 'com.antfortune.freeline:gradle:0.8.7'
    
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    
    allprojects {
        repositories {
            jcenter()
        }
    }
    

    6 . 应用的混淆配置文件,代码如下:

    -keepclassmembers class fqcn.of.javascript.interface.for.webview {
       public *;
    }
    #webView js调用不混淆,否则取不到数据
    -keepclassmembers class com.zyp.ui.WebActivity$* {
        <methods>;
    }
    
    #shrink,测试后发现会将一些无效代码给移除,即没有被显示调用的代码,该选项 表示 不启用 shrink。
    #-dontshrink
    #指定重新打包,所有包重命名,这个选项会进一步模糊包名,将包里的类混淆成n个再重新打包到一个个的package中
    #-flattenpackagehierarchy
    #优化时允许访问并修改有修饰符的类和类的成员
    -allowaccessmodification
    #不跳过(混淆) jars中的 非public classes   默认选项
    -dontskipnonpubliclibraryclassmembers
    #忽略警告
    -ignorewarnings
    #指定代码的压缩级别
    -optimizationpasses 5
    #不使用大小写混合类名
    -dontusemixedcaseclassnames
    #不去忽略非公共的库类
    -dontskipnonpubliclibraryclasses
    #不启用优化  不优化输入的类文件
    -dontoptimize
    #不预校验
    -dontpreverify
    #混淆时是否记录日志
    -verbose
    #混淆时所采用的算法
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
    #保护注解
    -renamesourcefileattribute SourceFile
    #保持源文件和行号的信息,用于混淆后定位错误位置
    -keepattributes SourceFile,LineNumberTable
    #保持含有Annotation字符串的 attributes
    -keepattributes *Annotation*
    #过滤泛型
    -keepattributes Signature
    -keepattributes Exceptions,InnerClasses
    
    -dontwarn org.apache.**
    -dontwarn android.support.**
    
    #基础配置
    # 保持哪些类不被混淆
    # 系统组件
    -keep public class * extends android.app.Fragment
    -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 com.android.vending.licensing.ILicensingService
    #如果有引用v4包可以添加下面这行
    -keep public class * extends android.support.v4.app.Fragment
    #自定义View
    -keep public class * extends android.view.View
    # V4,V7
    -keep class android.support.constraint.**{ *; }
    -keep class android.support.v4.**{ *; }
    -keep class android.support.v7.**{ *; }
    -keep class android.webkit.**{*;}
    -keep interface android.support.v4.app.** { *; }
    #保持 本化方法及其类声明
    -keepclasseswithmembers class * {
        native <methods>;
    }
    #保持view的子类成员: getter setter
    -keepclassmembers public class * extends android.view.View {
       void set*(***);
       *** get*();
    }
    #保持Activity的子类成员:参数为一个View类型的方法   如setContentView(View v)
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    #保持枚举类的成员:values方法和valueOf  (每个enum 类都默认有这两个方法)
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    #保持Parcelable的实现类和它的成员:类型为android.os.Parcelable$Creator 名字任意的 属性
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    #保持 任意包名.R类的类成员属性。  即保护R文件中的属性名不变
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    # 记录生成的日志数据,在 proguard 目录下
    
    -dump class_files.txt
    
    -printseeds seeds.txt
    
    -printusage unused.txt
    
    -printmapping mapping.txt
    
    
    -keepclasseswithmembernames class * {
        native <methods>;
    }
    
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet);
    }
    
    -keepclasseswithmembers class * {
        public <init>(android.content.Context, android.util.AttributeSet, int);
    }
    
    -keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
    }
    
    -keepclassmembers enum * {
        public static **[] values();
        public static ** valueOf(java.lang.String);
    }
    
    -keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
    }
    -keepnames class * implements android.os.Parcelable {
        public static final ** CREATOR;
    }
    
    -dontwarn java.util.**
    -keep class java.util.** {*; }
    
    -dontwarn org.apache.http.**
    -keep class org.apache.http.** {*; }
    
    -keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
    }
    
    -keep public class * implements java.io.Serializable {*;}
    
    -keepclassmembers class **.R$* {
        public static <fields>;
    }
    
    # ======================= 以上是混淆的基础配置================================
    # ======================= 以下是混淆的第三方包的配置================================
    
    
    # ======================= Gson 混淆================================
    -keepattributes *Annotation*
    -keep class sun.misc.Unsafe { *; }
    -keep class com.idea.fifaalarmclock.entity.***
    -keep class com.google.gson.stream.** { *; }
    
    # ======================= Umeng 混淆================================
    -keepclassmembers class * {
       public <init> (org.json.JSONObject);
    }
    #这是由于SDK中的部分代码使用反射来调用构造函数, 如果被混淆掉, 在运行时会提示"NoSuchMethod"错误。
    #另外,由于SDK需要引用导入工程的资源文件,通过了反射机制得到资源引用文件R.java,但是在开发者通过proguard等混淆/优化工具处理apk时,proguard可能会将R.java删除,如果遇到这个问题,请在proguard配置文件中添加keep命令如:
    -keep public class com.zyp.R$*{
        public static final int *;
    }
    -keep class com.umeng.**
    -keep public class com.idea.fifaalarmclock.app.R$*{
        public static final int *;
    }
    
    -keep public class com.umeng.fb.ui.ThreadView {
    }
    -dontwarn com.umeng.**
    -dontwarn org.apache.commons.**
    -keep public class * extends com.umeng.**
    -keep class com.umeng.** {*; }
    
    
    # ======================= pinying4j 混淆================================
    -dontwarn com.hp.hpl.sparta.**
    -keep class com.hp.hpl.sparta.**{*;}
    -dontwarn net.sourceforge.pinyin4j.**
    -keep class net.sourceforge.pinyin4j.**{*;}
    -dontwarn demo.**
    -keep class demo.**{*;}
    
    # ======================= volley 混淆================================
    -dontwarn com.android.volley.**
    -keep class com.android.volley.**{*;}
    
    # ======================= fastjson 混淆================================
    -dontwarn com.alibaba.fastjson.**
    -keep class com.alibaba.fastjson.** { *; }
    # ======================= alipay 混淆================================
    -keep class com.alipay.android.app.IAlixPay{*;}
    -keep class com.alipay.android.app.IAlixPay$Stub{*;}
    -keep class com.alipay.android.app.IRemoteServiceCallback{*;}
    -keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
    -keep class com.alipay.sdk.app.PayTask{ public *;}
    -keep class com.alipay.sdk.app.AuthTask{ public *;}
    -keep class com.alipay.mobilesecuritysdk.*
    -keep class com.ut.*
    
    # ======================= weixin 混淆================================
    -keep class com.tencent.mm.** { *; }
    
    # ======================= okio ================================
    -dontwarn okio.**
    -keep class okio.**{*;}
    -keep interface okio.**{*;}
    
    
    # ======================= activation.jar ================================
    -dontwarn javax.activation.**
    -keep class javax.activation.**{*;}
    -dontwarn com.sun.activation.registries.**
    -keep class com.sun.activation.registries.**{*;}
    
    # ======================= additionnal.jar ================================
    -dontwarn myjava.awt.datatransfer.**
    -keep class myjava.awt.datatransfer.**{*;}
    -dontwarn org.apache.harmony.**
    -keep class org.apache.harmony.**{*;}
    
    
    # ======================= RxAndroid,RxJava ================================
    -dontwarn sun.misc.**
    -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
       long producerIndex;
       long consumerIndex;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
        rx.internal.util.atomic.LinkedQueueNode producerNode;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
        rx.internal.util.atomic.LinkedQueueNode consumerNode;
    }
    
    #======================= httpmime =======================
    -keep class org.apache.http.entity.mime.** {*;}
    #======================= zxing =======================
    -keep class com.google.zxing.** { *; }
    
    #======================= simplelatlng =======================
    -keep class com.javadocmd.simplelatlng.** {*;}
    
    # =======================universal-image-loader ================================
    -keep class com.nostra13.universalimageloader.** {*;}
    
    # ======================= 百度地图  ================================
    -keep class com.baidu.** {*;}
    -keep class vi.com.** {*;}
    -dontwarn com.baidu.**
    
    # ======================= 高德地图  ================================
    # 3D 地图
    -keep   class com.amap.api.maps.**{*;}
    -keep   class com.autonavi.amap.mapcore.*{*;}
    -keep   class com.amap.api.trace.**{*;}
    
    # 定位
    -keep class com.amap.api.location.**{*;}
    -keep class com.amap.api.fence.**{*;}
    -keep class com.autonavi.aps.amapapi.model.**{*;}
    
    #搜索
    -keep   class com.amap.api.services.**{*;}
    
    #2D地图
    -keep class com.amap.api.maps2d.**{*;}
    -keep class com.amap.api.mapcore2d.**{*;}
    
    #导航
    -keep class com.amap.api.navi.**{*;}
    -keep class com.autonavi.**{*;}
    
    #讯飞
    -keep class com.iflytek.**{*;}
    
    
    # ======================= app javabean 混淆================================
    -keep class com.zyp.bean.**{*;}
    
    
    ##---------------Begin:retrofit+rxjava----------------------
    -dontwarn javax.annotation.**
    -dontwarn javax.inject.**
    # OkHttp3
    -dontwarn com.squareup.okhttp.**
    -keep class com.squareup.okhttp.** { *;}
    -keep interface okhttp3.**{*;}
    -dontwarn okhttp3.logging.**
    -keep class okhttp3.internal.**{*;}
    -dontwarn okhttp3.**
    -keep class okhttp3.** { *;}
    -dontwarn okio.**
    # Retrofit
    -dontwarn retrofit2.**
    -keep class retrofit2.** { *; }
    -keepattributes Signature
    -keepattributes Exceptions
    # RxJava RxAndroid
    -dontwarn sun.misc.**
    -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
        long producerIndex;
        long consumerIndex;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
        rx.internal.util.atomic.LinkedQueueNode producerNode;
    }
    -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
        rx.internal.util.atomic.LinkedQueueNode consumerNode;
    }
    
    
    -dontnote android.webkit.**
    -dontnote java.util.**
    
    ##---------------Inmobi----------------------
    
    -keepattributes SourceFile,LineNumberTable -keep class com.inmobi.** { *; }
    -keep public class com.google.android.gms.**
    -dontwarn com.google.android.gms.**
    -dontwarn com.squareup.picasso.**
    -keep class com.google.android.gms.ads.identifier.AdvertisingIdClient{
    public *;
    }
    # skip the Picasso library classes
    -keep class com.squareup.picasso.** {*;}
    -dontwarn com.squareup.picasso.**
    -dontwarn com.squareup.okhttp.**
    # skip Moat classes
    -keep class com.moat.** {*;}
    -dontwarn com.moat.**
    

    7 . 此Demo的功能,可以在应用内切换Base_Url,退出登录时还原默认的Base_Url ,导出应用的私有数据到SD卡上,个人觉得这几个功能,是我们开发app时很需要的功能,如下所示:

    image.png

    8 . 混淆前后文件目录变化如下图所示,其中mapping.txt文件为混淆的映射文件,每个版本要注意保存起来(Umeng上需要导入这个文件的)。

    image.png

    9 . 对系统Log类的封装Logger类,可以在控制台打印出如下图所示的功能,主要实现代码如下:

    StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[4];
    StringBuilder sb = new StringBuilder();
    sb.append("(")
            .append(stackTrace.getFileName())
            .append(":")
            .append(stackTrace.getLineNumber())
            .append(")")
            .append("#")
            .append(stackTrace.getMethodName())
            .append(":")
            .append(CommonUtil.unicode2GBK(sb1.toString()));//服务器返回的汉字可能是unicode编码,所以在此转成GBK
    
    image.png

    10 . 最后还有一个小Tips要送大家,大家其实发现了我应用中使用的全是AppConfig.IS_DEBUG而不是BuildConfig.DEBUG,这是为什么呢?主要是为了避免导错BuildConfig的包名,如下图所示:

    image.png

    看看随便进入一个android.support.design的BuildConfig,BuildConfig.DEBUG其实是为false的,其实我们希望BuildConfig.DEBUG为true,�但是事与愿违,而且这个错误还不容易发现。


    image.png

    为什么用AppConfig.IS_DEBUG就不会出现这样的问题呢,因为这是在我们自己的app下定义的,在那定义的?如下图所示,其实是在build.gradle中定义的,build.gradle可以定义很多类型的变量,可以很方便的达到我们需要的效果:

    image.png

    而在AppConfig我又封装了一层,避免了其他library中的build.gradle也定义了IS_DEBUG字段,所以只要AppConfig中的导包正确,就不会出现错误了,所以使用build.gradle中定义的字段时候,请务必再封装一层,代码如下图所示:

    import com.zyp.BuildConfig;
    
    public class AppConfig {
        /**在build.gradle中配置的变量*/
        public static String BASE_URL = BuildConfig.BASE_URL;
        /** 默认的base url */
        public final static String DEFAULT_BASE_URL = BuildConfig.BASE_URL;
        public final static String APPLICATION_ID = BuildConfig.APPLICATION_ID;
        public final static int VERSION_CODE = BuildConfig.VERSION_CODE;
        public final static boolean IS_LOG = BuildConfig.IS_LOG;
        public final static boolean IS_DEBUG = BuildConfig.IS_DEBUG;
        public final static String[] BASE_TEST_URL = BuildConfig.BASE_TEST_URL;
    }
    
    

    Demo下载地址
    GitHub地址

    相关文章

      网友评论

      • 沐小晨曦:对不起,来晚了,但是还是要给博主一颗小心心。:sparkling_heart:
      • 汪简书:良心UP主 :)
        还有个tip:在 onActivityResumed() 中可以设置一个当前Activity sCurrentActivityWeakRef ,这样可以在dialog,Pop中得到Activity。还有最好用 WeakReference<Activity> sCurrentActivityWeakRef 保存ta
      • Chaunch_Cheng:我会持续关注

      本文标题:开发一个优秀的Android应用你必须要加入的代码及配置

      本文链接:https://www.haomeiwen.com/subject/afsyqxtx.html