Bugly热更新集成详解

前言

更新一直是一个很重要的点,从最开始的全量更新,到我之前讲过的增量更新,当然也到今天我要讲的bugly热更新。

今天涉及的内容:

  1. bugly热更新前的准备
    1.1 bugly上注册账号,新建产品
    1.2 项目前期准备
  2. 热更新集成步骤
    2.1 添加插件依赖
    2.2 集成SDK
    2.3 app_module的build.gradle中添加tinker-support.gradle引用
    2.4 新建tinker-support.gradle文件
    2.5 初始化SDK
    2.6 AndroidManifest.xml配置
    2.7 混淆配置
  3. 编译基包和补丁包
    3.1 编译基包
    3.2 启动apk,上报联网数据
    3.3 编译补丁包
  4. 上传补丁包到bugly
  5. 热更新集成注意的问题
    5.1 在编译基包完成后,bakApk文件夹下缺少app-release-mapping.txt文件
    5.2 生成的基包apk app-release.apk 安装后不能运行
    5.3 编译完补丁包后,项目/app/outputs/patch/ 文件夹下无文件
    5.4 编译完补丁包后,项目/app/outputs/patch/ 文件夹下无patch_release_7zip.apk文件
    5.5 打补丁包生成错误
    5.6 bugly上传补丁包失败
    5.7 bugly上传补丁包时,提示没有创建时间等信息
    5.8 bugly上传补丁包时,没有自动提示目标版本
    5.9 如何判断基包联网上传成功
    5.10 补丁包已经上传了,但是运行手机上的apk,并没有热更新
  6. 更多相关帮助

一. bugly热更新前的准备

1.1 bugly上注册账号,新建产品

这一操作比较简单,就是登录bugly官网(没有的话自己注册一个账号),然后新建一个产品,在产品设置界面获得该产品AppId(假设此时我获得的AppId=hyeieooe)

1.2 项目前期准备

你项目在前期需要做以下准备:
- 在app_module的build.gradle中配置项目签名
也即是你需要给你的项目在·build.gradle`中配置打包签名。具体签名操作可以参考:
Gradle中给项目签名

- 给你的项目添加混淆配置
为了给增加app的密保性能且为了更好的接入bugly热更新功能,你需要给自己的项目添加混淆配置。
给项目加入混淆配置的步骤你可以参考androidstudio混淆签名
然后这里,我添加一个我使用的混淆文件proguard-rules.pro,代码如下:

-dontshrink
-flattenpackagehierarchy
#指定压缩级别
-optimizationpasses 7
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
#不跳过非公共的库的类成员
-dontskipnonpubliclibraryclassmembers

#混淆时采用的算法 后面的参数是一个过滤器,这个过滤器是谷歌推挤的算法
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*

#把混淆类中的方法名也混淆了
-useuniqueclassmembernames

#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification

#包明不混合大小写
-dontusemixedcaseclassnames

#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#不混淆输入的类文件
-dontobfuscate

 #混淆时是否记录日志
-verbose

# 混淆时不做预校验 Android 不需要做 preverify,去掉可加快混淆速度
-dontpreverify

#将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile

#保留行号
-keepattributes SourceFile,LineNumberTable,Deprecated

#保护注解
-keepattributes *Annotation*,InnerClasses,Deprecated


# 泛型与反射
-keepattributes Signature

-keepattributes EnclosingMethod

-keepattributes *Annotation*

-keep class package.classname{*;}

#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
    native ;
}

#不提示兼容库的错误警告
-dontwarn android.support.**

#保持所有实现 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();
}


# 保持测试相关的代码
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**


#Fragment不需要在AndroidManifest.xml中注册,需要额外保护下
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.support.v7.app.AppCompatActivity
-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 java.lang.Throwable {*;}
-keep public class * extends java.lang.Exception {*;}
-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.os.IInterface
-keep interface android.support.constraint.** { *; }
-keep class androidx.** {*;}
-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);
}


# 保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
 public void *(android.view.View);
}


-keep class * extends android.support.v4.app.FragmentManager{ *; }
-keepclasseswithmembernames class android.support.v4.widget.ViewDragHelper{ *; }


#不混淆资源类及其方法
-keep class **.R$* {
 *;
}


# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
    void *(**On*Event);
    void *(**On*Listener);
}

# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {
    public (android.content.Context);
    public (android.content.Context, android.util.AttributeSet);
    public (android.content.Context, android.util.AttributeSet, int);
    public void set*(...);

}

 # 保持枚举 enum 类不被混淆
-keepclassmembers enum * {
 public static **[] values();
 public static ** valueOf(java.lang.String);
}

# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
 public static final android.os.Parcelable$Creator *;
}


#-----------处理实体类---------------
# 在开发的时候我们可以将所有的实体类放在一个包内,这样我们写一次混淆就行了。
#-keep public class com.test.models.** {
#    public void set*(***);
#    public *** get*();
#    public *** is*();
#
#}

 #保护WebView对HTML页面的API不被混淆
-keep class **.Webview2JsInterface { *; }


#如果项目中用到了WebView的复杂操作
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String);
}

# 移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用
# 记得proguard-android.txt中一定不要加-dontoptimize才起作用
# 另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制
#-assumenosideeffects class android.util.Log {
#    public static int v(...);
#    public static int i(...);
#    public static int w(...);
#    public static int d(...);
#    public static int e(...);
#}

#############################################
#
# 项目中特殊处理部分
#
#############################################

#-----------处理反射类---------------



#-----------处理js交互---------------



#-----------处理第三方依赖库---------

-printmapping mapping.txt

#EventBus
-keepattributes *Annotation*
-keepclassmembers class ** {
    @org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }


# Glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}


# ButterKnife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
    @butterknife.* ;
}
-keepclasseswithmembernames class * {
    @butterknife.* ;
}



# 极光推送
-dontoptimize
-dontpreverify
-dontwarn cn.jpush.**
-keep class cn.jpush.** { *; }
-keep class * extends cn.jpush.android.helpers.JPushMessageReceiver { *; }

-dontwarn cn.jiguang.**
-keep class cn.jiguang.** { *; }

 -keep public class cn.jiguang.analytics.android.api.** {
        *;
    }


-dontwarn com.google.**
-keep class com.google.gson.** {*;}
-keep class com.google.protobuf.** {*;}


# OkHttp
-keep class com.squareup.okhttp.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-dontwarn com.squareup.okhttp.**


# OkHttp3
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okio.**

-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**

# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**

# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase

# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*

# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform

# Okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep class okio.**{*;}
-dontwarn okio.**

-keep class org.litepal.** {
    *;
}

-keep class * extends org.litepal.crud.DataSupport {
    *;
}

-keep class * extends org.litepal.crud.LitePalSupport {
    *;
}

# Retrolambda
-dontwarn java.lang.invoke.*

## ---------Retrofit混淆方法---------------
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
# OkHttp3
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.**{*;}
-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 rx.internal.util.PlatformDependent

# Gson
-keepattributes EnclosingMethod
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.stream.** { *; }
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# 使用Gson时需要配置Gson的解析对象及变量都不混淆。不然Gson会找不到变量。
# 将下面替换成自己的实体类
-keep class com.inm.models.** { *; }


-keep public class * extends android.app.Activity
-keep public class * extends android.support.v4.app.Fragment
-keepclassmembers class * extends android.app.Activity {
   public int getContainerViewId();
   public boolean onRiggerBackPressed();
   public void onFragmentResult(int,int,android.os.Bundle);
   public void onLazyLoadViewCreated(android.os.Bundle);
   public int[] getPuppetAnimations();
   public String getFragmentTag();
   public boolean onInterruptBackPressed();
}
-keepclassmembers class * extends android.support.v4.app.Fragment {
   public int getContainerViewId();
   public boolean onRiggerBackPressed();
   public void onFragmentResult(int,int,android.os.Bundle);
   public void onLazyLoadViewCreated(android.os.Bundle);
   public int[] getPuppetAnimations();
   public String getFragmentTag();
   public boolean onInterruptBackPressed();
}


 # androidx 的混淆代码
 -keep class com.google.android.** {*;}
 -keep class androidx.** {*;}
 -keep public class * extends androidx.**
 -keep interface androidx.** {*;}
 -dontwarn com.google.android.material.**
 -dontnote com.google.android.material.**
 -dontwarn androidx.**

 -keepattributes *Annotation*
 -keepattributes *JavascriptInterface*
 -keep class android.webkit.JavascriptInterface {*;}


  # ------------------ Keep LineNumbers and properties ---------------- #
  -keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
  # --------------------------------------------------------------------------







  #---------------------------------------------------------------------------


  #------------------  下方是android平台自带的排除项,这里不要动         ----------------

-keep public class * extends android.app.Activity{
    public ;
    public ;
}
-keep public class * extends android.app.Application{
    public ;
    public ;
}
-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

-keepclassmembers enum * {
      public static **[] values();
      public static ** valueOf(java.lang.String);
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public (android.content.Context, android.util.AttributeSet, int);
}

-keepattributes *Annotation*

-keepclasseswithmembernames class *{
    native ;
}

-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}

  #------------------  下方是共性的排除项目         ----------------
  # 方法名中含有“JNI”字符的,认定是Java Native Interface方法,自动排除
  # 方法名中含有“JRI”字符的,认定是Java Reflection Interface方法,自动排除
-keepclasseswithmembers class * {
      ... *JNI*(...);
}

-keepclasseswithmembernames class * {
    ... *JRI*(...);
}

-keep class **JNI* {*;}



-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }
-keep public class com.tencent.tinker.entry.TinkerApplicationInlineFence {
    (...);
    void attachBaseContext(com.tencent.tinker.loader.app.TinkerApplication, android.content.Context);
}

-keep public class com.tencent.bugly.beta.tinker.TinkerPatchReflectApplication {
    (...);
}

这里需要注意的是,如果你项目在混淆的时候报 R8错误,那么你需要在你项目的gradle.properties文件中加入以下代码以关闭R8相关处理:

# 混淆关闭 R8
android.enableR8=false

二.热更新集成步骤

下面开始进入正题,也即是bugly热更新的集成。

2.1 添加插件依赖

工程根目录下“build.gradle”文件中添加:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        //tinkersupport插件
        classpath "com.tencent.bugly:tinker-support:1.2.0"
    }
}
2.2 集成SDK

app_modulebuild.gradle中添加如下配置:

  android {
        defaultConfig {
        //开启multidex
        multiDexEnabled true

        ndk {
            // 设置支持的SO库架构
            abiFilters 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'//,'armeabi'
           }
        }
  }


  dependencies {
    //============bugly热更新======
    // 多dex配置
    implementation "com.android.support:multidex:1.0.1"
    // 集成Bugly热更新aar(本地集成使用方式)
    //compile(name: 'bugly_crashreport_upgrade-1.3.2', ext: 'aar')
    // 远程仓库集成方式(推荐)
    //compile 'com.tencent.bugly:crashreport_upgrade:1.3.8'
    implementation 'com.tencent.bugly:crashreport_upgrade:1.3.8'
    //1. 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
    //2.为了便于解答问题,这里的tinker版本建议跟随此处demo设置,如果微信更新了tinker版本,bugly会定期同步更新
    implementation 'com.tencent.tinker:tinker-android-lib:1.9.14.3'
    implementation 'com.tencent.bugly:nativecrashreport:2.2.0'
    // walle(多渠道使用)
    // compile 'com.meituan.android.walle:library:1.1.3'
    //=============================
  }
2.3 app_module的build.gradle中添加tinker-support.gradle引用

app_modulebuild.gradle的文件头部添加tinker-support.gradle文件的引用,如下:

// 依赖插件脚本
apply from: 'tinker-support.gradle'
2.4 新建tinker-support.gradle文件

项目\app\路径下新建tinker-support.gradle文件,具体路径如下

Bugly热更新集成详解_第1张图片
image.png

然后 tinker-support.gradle文件代码如下:

你可能感兴趣的:(Bugly热更新集成详解)