Android热更新集成之Bugly

作者: Wocus | 来源:发表于2018-07-20 10:43 被阅读21次

Bugly是鹅厂的一个集成异常上报,运营统计,在线升级,热更新的框架;

与传统的热更新相比,这个不需要搭建后台,不需要知道补丁是如何生成的,我只简述使用Bugly热更新成功的一种例子和我遇到的问题

集成

①工程根目录下“build.gradle”文件中添加:
classpath "com.tencent.bugly:tinker-support:1.1.2"
②在app module的“build.gradle”文件中添加(示例配置):
android {
        defaultConfig {
          ndk {
            //设置支持的SO库架构
            abiFilters 'armeabi' //, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
          }
        }
      }
      dependencies {
          compile "com.android.support:multidex:1.0.1" // 多dex配置
          //注释掉原有bugly的仓库
          //compile 'com.tencent.bugly:crashreport:latest.release'//其中latest.release指代最新版本号,也可以指定明确的版本号,例如1.3.4
          compile 'com.tencent.bugly:crashreport_upgrade:1.3.5'
          // 指定tinker依赖版本(注:应用升级1.3.5版本起,不再内置tinker)
          compile 'com.tencent.tinker:tinker-android-lib:1.9.6'
          compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新版本号,也可以指定明确的版本号,例如2.2.0
      }
③在APP目录下添加tinker-support.gradle文件
3

内容如下:

apply plugin: 'com.tencent.bugly.tinker-support'

def bakPath = file("${buildDir}/bakApk/")

/**
 * 此处填写每次构建生成的基准包目录
 */
def baseApkDir = "app-0719-16-37-01"

/**
 * 对于插件各参数的详细解析请参考
 */
tinkerSupport {

    // 开启tinker-support插件,默认值true
    enable = true

    // 指定归档目录,默认值当前module的子目录tinker
    autoBackupApkDir = "${bakPath}"

    // 是否启用覆盖tinkerPatch配置功能,默认值false
    // 开启后tinkerPatch配置不生效,即无需添加tinkerPatch
    overrideTinkerPatchConfiguration = true

    // 编译补丁包时,必需指定基线版本的apk,默认值为空
    // 如果为空,则表示不是进行补丁包的编译
    // @{link tinkerPatch.oldApk }
    baseApk = "${bakPath}/${baseApkDir}/app-release.apk"

    // 对应tinker插件applyMapping
    baseApkProguardMapping = "${bakPath}/${baseApkDir}/app-release-mapping.txt"

    // 对应tinker插件applyResourceMapping
    baseApkResourceMapping = "${bakPath}/${baseApkDir}/app-release-R.txt"

    // 构建基准包和补丁包都要指定不同的tinkerId,并且必须保证唯一性
    tinkerId = "patch-1.0.1"

    // 构建多渠道补丁时使用
    // buildAllFlavorsDir = "${bakPath}/${baseApkDir}"

    // 是否启用加固模式,默认为false.(tinker-spport 1.0.7起支持)
    // isProtectedApp = true

    // 是否开启反射Application模式
    enableProxyApplication = true

    // 是否支持新增非export的Activity(注意:设置为true才能修改AndroidManifest文件)
    supportHotplugComponent = true

}
④在app module的“build.gradle”文件中添加:
4
// 依赖插件脚本
apply from: 'tinker-support.gradle'
⑤AndroidManifest.xml配置

加入权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

加入Activity:

<activity
    android:name="com.tencent.bugly.beta.ui.BetaActivity"
    android:configChanges="keyboardHidden|orientation|screenSize|locale"
    android:theme="@android:style/Theme.Translucent" />

加入配置FileProvider:

 <provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="${applicationId}.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"/>
</provider>

假如你已经使用了FileProvider,就加入此配置

<provider
    android:name=".util.BuglyFileProvider"
    android:authorities="${applicationId}.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true"
    tools:replace="name,authorities,exported,grantUriPermissions">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/provider_paths"
        tools:replace="name,resource"/>
</provider>
image.png
⑥在res文件夹下新增xml文件夹,新增provider_paths.xml文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- /storage/emulated/0/Download/${applicationId}/.beta/apk-->
    <external-path name="beta_external_path" path="Download/"/>
    <!--/storage/emulated/0/Android/data/${applicationId}/files/apk/-->
    <external-path name="beta_external_files_path" path="Android/data/"/>
</paths>
⑦为了避免混淆SDK,在Proguard混淆文件中增加以下配置:
-dontwarn com.tencent.bugly.**
-keep public class com.tencent.bugly.**{*;}
# tinker混淆规则
-dontwarn com.tencent.tinker.**
-keep class com.tencent.tinker.** { *; }

如果你使用了support-v4包,你还需要配置以下混淆规则:

-keep class android.support.**{*;}
⑧Application配置
package com.wocus.wine.application;

import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;

import com.tencent.bugly.Bugly;
import com.tencent.bugly.beta.Beta;

/**
 * Created by Administrator on 2018/7/5.
 */

public class BaseApplication extends Application{
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(base);
        Beta.installTinker();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Bugly.init(this, "ce34683adf", true);
    }
}

到此已经集成完毕

使用

①打包基准包
image.png

注意加入keystore配置


image.png

注意一定要开启混淆,不然打包没有mapper文件

buildTypes {
        release {
            minifyEnabled true
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

打包成功之后,会在此目录有3个文件


image.png

app-release.apk则为你的基准包,上线发布的包,拿这个apk在手机上安装上报联网

打包补丁包

上线之后如果发现版本有Bug,可以打补丁包修复,Bug修复好了,去更改tinker-support.gradle文件

/**
 * 此处填写每次构建生成的基准包目录
 */
def baseApkDir = "app-0719-16-37-01"
// 构建基准包和补丁包都要指定不同的tinkerId,并且必须保证唯一性
 tinkerId = "patch-1.0.1"

tinkerId 一定不能和打包基准包的Id一样
我是这样定义的,基准报的tinkerId 为:base-版本号,补丁包为:patch-版本号,版本号都一致对应基准包的版本

baseApkDir 则为基准包发布的那个目录,上图有自己可以去看看
然后编译补丁包


image.png

编译成功之后会在此目录有3个文件,这个文件就是你需要上传的补丁包了


image.png

然后拿这个去Bugly平台上传,就OK了

遇到的问题

1.打包出来基准包的是为签名apk

A:需要在build.gradle配置签名文件,举个栗子:

signingConfigs {
        release {
            keyAlias 'wine'
            keyPassword '123456'
            storeFile file('C:/Project/Android Studio Project/wine/wine.jks')
            storePassword '123456'
        }
    }
2.打包出来的基准包没有mapper文件

A:需要在build.gradle开启混肴

buildTypes {
        release {
            minifyEnabled true
            signingConfig signingConfigs.release
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
3.开启混肴之后,打包基准报报错

A:假如你之前项目都没有配置混肴文件,对此来说需要花费不少时间,你把下面文件拷贝去混肴文件就OK了


-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.**

如果集成中有什么问题,欢迎联系我QQ752422962

相关文章

网友评论

本文标题:Android热更新集成之Bugly

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