集成騰訊瀏覽服務(wù)TBS以及遇到的問題

序言

騰訊瀏覽服務(wù)功能強(qiáng)大,穩(wěn)定,集成還算是比較簡(jiǎn)單的,比原生的webview強(qiáng)。最主要的是可以瀏覽PDF,Word文檔,方便不少。此篇文章主要不是在講集成,雖然集成的篇幅多些,但是我寫的最重要的目的是我在實(shí)際使用過程中碰到的問題,以及解決方案。如果已經(jīng)成功集成的了,可直接看其他問題,可能會(huì)有你想要的。

TBS文檔接入地址

基本上的話照著這個(gè)文檔接入是沒有什么問題的,但是打開本地文件的時(shí)候,還是出現(xiàn)了一點(diǎn)小問題,因?yàn)槲臋n里面沒有說(shuō)明。

基礎(chǔ)配置

現(xiàn)在的Android開發(fā)都使用Android Studio了,所以只需要在app的build.gradle里面添加依賴,這份文章的日期是2020/9/30,最新id版本是下面這個(gè)

api 'com.tencent.tbs.tbssdk:sdk:43939'

權(quán)限配置

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

混淆配置

-dontwarn dalvik.**
-dontwarn com.tencent.smtt.**

-keep class com.tencent.smtt.** {
    *;
}

-keep class com.tencent.tbs.** {
    *;
}

異常上報(bào)配置

為了提高合作方的webview場(chǎng)景穩(wěn)定性,及時(shí)發(fā)現(xiàn)并解決x5相關(guān)問題,當(dāng)客戶端發(fā)生crash等異常情況并上報(bào)給服務(wù)器時(shí)請(qǐng)務(wù)必帶上x5內(nèi)核相關(guān)信息。x5內(nèi)核異常信息獲取接口為:com.tencent.smtt.sdk.WebView.getCrashExtraMessage(context)。以bugly日志上報(bào)為例:

UserStrategy strategy = new UserStrategy(appContext);
  strategy.setCrashHandleCallback(new CrashReport.CrashHandleCallback() {
    public Map<String, String> onCrashHandleStart(
            int crashType, 
            String errorType, 
            String errorMessage, 
            String errorStack) {

            LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
            String x5CrashInfo = com.tencent.smtt.sdk.WebView.getCrashExtraMessage(appContext);
            map.put("x5crashInfo", x5CrashInfo);
            return map;
    }
    @Override
    public byte[] onCrashHandleStart2GetExtraDatas(
            int crashType, 
            String errorType, 
            String errorMessage, 
            String errorStack) {
            try {
                return "Extra data.".getBytes("UTF-8");
            } catch (Exception e) {
                return null;
            }
    }
  });

  CrashReport.initCrashReport(appContext, APPID, true, strategy);

首次初始化冷啟動(dòng)優(yōu)化

TBS內(nèi)核首次使用和加載時(shí),ART虛擬機(jī)會(huì)將Dex文件轉(zhuǎn)為Oat,該過程由系統(tǒng)底層觸發(fā)且耗時(shí)較長(zhǎng),很容易引起anr問題,解決方法是使用TBS的 ”dex2oat優(yōu)化方案“。

(1). 設(shè)置開啟優(yōu)化方案

// 在調(diào)用TBS初始化、創(chuàng)建WebView之前進(jìn)行如下配置 
HashMap map = new HashMap(); 
map.put(TbsCoreSettings.TBS_SETTINGS_USE_SPEEDY_CLASSLOADER, true); 
map.put(TbsCoreSettings.TBS_SETTINGS_USE_DEXLOADER_SERVICE, true); 
QbSdk.initTbsSettings(map);

(2). 增加Service聲明

  1. 在AndroidManifest.xml中增加內(nèi)核首次加載時(shí)優(yōu)化Service聲明。
  2. 該Service僅在TBS內(nèi)核首次Dex加載時(shí)觸發(fā)并執(zhí)行dex2oat任務(wù),任務(wù)完成后自動(dòng)結(jié)束。
<service 
android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
android:label="dexopt"
android:process=":dexopt" >
</service>

初始化X5內(nèi)核

 QbSdk.setDownloadWithoutWifi(true);
    QbSdk.setTbsListener(
        new TbsListener() {
          @Override
          public void onDownloadFinish(int i) {
            Log.d("QbSdk", "onDownloadFinish -->下載X5內(nèi)核完成:" + i);
          }

          @Override
          public void onInstallFinish(int i) {
            Log.d("QbSdk", "onInstallFinish -->安裝X5內(nèi)核進(jìn)度:" + i);
          }

          @Override
          public void onDownloadProgress(int i) {
            Log.d("QbSdk", "onDownloadProgress -->下載X5內(nèi)核進(jìn)度:" + i);
          }
        });

    QbSdk.PreInitCallback cb =
        new QbSdk.PreInitCallback() {
          @Override
          public void onViewInitFinished(boolean arg0) {
            // x5內(nèi)核初始化完成的回調(diào),true表x5內(nèi)核加載成功,否則表加載失敗,會(huì)自動(dòng)切換到系統(tǒng)內(nèi)核。
            Log.d("QbSdk", " 內(nèi)核加載 " + arg0);
          }

          @Override
          public void onCoreInitFinished() {}
        };

    // x5內(nèi)核初始化接口
    QbSdk.initX5Environment(getApplicationContext(), cb);

WebView接入

這部分其實(shí)就是將原生webview的東西全部換成帶有com.tencent.smtt包名的,TBS文檔上有介紹,這里就不做說(shuō)明了。

文件接入

這個(gè)應(yīng)該才是重點(diǎn)。

在APP內(nèi)部打開文件

APP內(nèi)部打開使用的是TBS里面的TbsReaderView,在我Demo中有示例??梢钥次业?a target="_blank">TBSDemo

這里有可能會(huì)碰到一個(gè)問題就是已經(jīng)在一個(gè)頁(yè)面使用TbsReaderView打開了文件,但是跳轉(zhuǎn)到另一個(gè)界面的時(shí)候,還是使用TbsReaderView再打開文件,這時(shí)候就會(huì)顯示一直在加載中。目前我能想到的方法就是在onResume的時(shí)候重新初始化TbsReaderView,

mFlRoot.removeAllViews();
    mTbsReaderView = new TbsReaderView( mActivity, readerCallback );
    mTbsReaderView.setBackgroundColor(
        ContextCompat.getColor( mActivity, R.color.color_white ) );
    mFlRoot.addView(
        mTbsReaderView,
        new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT ) );

調(diào)用打開文件的代碼

private void openFile() {
    String extensionName = FileUtils.getFileType( mReaderFile.getPath() );
    Bundle bundle = new Bundle();
    bundle.putString( TbsReaderView.KEY_FILE_PATH, mReaderFile.getPath() );
    bundle.putString( TbsReaderView.KEY_TEMP_PATH, FileUtils.createCachePath( mActivity ) );
    boolean result = mTbsReaderView.preOpen( extensionName, false );
    MLog.i( "addTbsReaderView: " + result );
    if ( result ) {
      mTbsReaderView.openFile( bundle );
    }
  }

在onPause的時(shí)候再調(diào)用。

if ( mTbsReaderView != null ) {
      mTbsReaderView.onStop();
    }

使用TBS的openFileReader打開文件

支持格式

TBS已提供9種主流文件格式的本地打開,如果您需要使用更高級(jí)的能力請(qǐng)使用QQ瀏覽器打開文件

  • 接入TBS可支持打開文件格式:doc、docx、ppt、pptx、xls、xlsx、pdf、txt、epub
  • 調(diào)用QQ瀏覽器可打開:rar(包含加密格式)、zip(包含加密格式)、tar、bz2、gz、7z(包含加密格式)、doc、docx、ppt、pptx、xls、xlsx、txt、pdf、epub、chm、html/htm、xml、mht、url、ini、log、bat、php、js、lrc、jpg、jpeg、png、gif、bmp、tiff 、webp、mp3、m4a、aac、amr、wav、ogg、mid、ra、wma、mpga、ape、flac
接口介紹
public static int openFileReader(
    Context context, 
    String filePath, 
    HashMap<String, String> extraParams,
    ValueCallback<String> callback
)

(1)此方法在Qbsdk類下

(2)調(diào)用之后,優(yōu)先調(diào)起 QQ 瀏覽器打開文件。如果沒有安裝 QQ 瀏覽器,在 X5 內(nèi)核下調(diào)起簡(jiǎn)版 QB 打開文 件。如果使用的系統(tǒng)內(nèi)核,則調(diào)起文件閱讀器彈框。

(3)暫時(shí)只支持本地文件打開

context: 調(diào)起 miniqbActivitycontext。此參數(shù)只能是 activity 類型的 context,不能設(shè)置為 Application 的 context。 filePath: 文件路徑。格式為 android 本地存儲(chǔ)路徑格式,例如:/sdcard/Download/xxx.doc. 不支持 file:/// 格式。暫不支持在線文件。 extraParams: miniqb 的擴(kuò)展功能。為非必填項(xiàng),若無(wú)需特殊配置,默認(rèn)可傳入null。擴(kuò)展功能參考“文件功能定制” ValueCallback: 提供 miniqb 打開/關(guān)閉時(shí)給調(diào)用方回調(diào)通知,以便應(yīng)用層做相應(yīng)處理,您可以在出現(xiàn)以下回調(diào)時(shí)結(jié)束您的進(jìn)程,節(jié)約內(nèi)存占用。主要回調(diào)值如下:

filepath error
TbsReaderDialogClosed 
default browser
fileReaderClosed

返回值:

1:用 QQ 瀏覽器打開
2:用 MiniQB 打開
3:調(diào)起閱讀器彈框
-1:filePath 為空 打開失敗 
public static void closeFileReader(Context context)

主動(dòng)關(guān)閉文件打開ui,并清理相應(yīng)內(nèi)存占用。

接入示例
HashMap<String, String> params = new HashMap<String, String>(); 
params.put("style", "1"); 
params.put("local", "true"); 
params.put("memuData", jsondata); 
QbSdk.openFileReader(ctx,”/sdcard/xxx.doc”, params,callback);

到這你以為就能順利打開瀏覽文件了嗎?還是太年輕了,騰訊的文檔不給你挖點(diǎn)坑,讓你養(yǎng)成自己解決bug的習(xí)慣是不會(huì)罷休的。當(dāng)你滿心歡喜調(diào)用QbSdk.openFileReade的時(shí)候,log會(huì)給你報(bào)一個(gè)錯(cuò)。

QbSdk: Must declare com.tencent.smtt.utils.FileProvider in AndroidManifest above Android 7.0,please view document in x5.tencent.com

意思就是讓你在AndroidManifest.xml中添加provider,因?yàn)锳ndroid版本7.0訪問文件的方式改變了。這時(shí)候添加一下就可以了。

首先在AndroidManifest.xml添加以下代碼

    <provider
      android:name="com.tencent.smtt.utils.FileProvider"
      android:authorities="${applicationId}.provider"
      android:exported="false"
      android:grantUriPermissions="true">
      <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/x5webview_file_paths" />
    </provider>

然后在res文件夾下創(chuàng)建xml文件夾,如果有了則跳過,接著再創(chuàng)建一個(gè)x5webview_file_paths.xml的文件,內(nèi)容如下

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="sdcard" path="."/>
</paths>

再運(yùn)行,應(yīng)該是沒有問題的了,這里需要保證的是文件的路徑是要對(duì)的,因?yàn)椴荒茉诰€瀏覽,只能把文件下載到本地才能調(diào)用。這個(gè)錯(cuò)誤我看了很久的文檔都沒有找到,后面在網(wǎng)上搜索,給出了以下的代碼,

<provider
    android:name="com.tencent.smtt.utils.FileProvider"
    android:authorities="包名.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/xml文件名" />
</provider>

這錯(cuò)就錯(cuò)在android:authorities="包名.fileprovider",因?yàn)楹髞?lái)我去調(diào)用服務(wù)開啟的QbSdk的類中,看這個(gè)錯(cuò)誤發(fā)生的時(shí)機(jī),發(fā)現(xiàn)他們是通過類型+“.provider”來(lái)校驗(yàn)的,所以只要改成android:authorities="包名.provider"就可以了,這個(gè)錯(cuò)誤調(diào)試了很久,還是得在源碼中才能發(fā)現(xiàn)春天。

其他問題

使用TbsReaderView瀏覽文件夜間模式問題

我在使用小米10至尊版的時(shí)候,我的APP中沒有適配深黑模式,使用的主題是Theme.AppCompat.Light.NoActionBar,但是小米10還是強(qiáng)制性的把我的APP使用了深黑模式。并且我發(fā)現(xiàn),不止是我的APP,而是我手機(jī)上所有的APP都是如此,不管有沒有適配,都使用了深黑模式,也就是夜間模式。這就導(dǎo)致了一個(gè)問題,使用TbsReaderView來(lái)瀏覽文件的時(shí)候,背景是黑色的,字體的顏色也是有點(diǎn)黑,導(dǎo)致文檔看的不清楚,后來(lái)我在閱讀TbsReaderView源碼的時(shí)候,發(fā)現(xiàn)可以設(shè)置強(qiáng)制不使用夜間模式。加入以下代碼即可。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
      //不使用黑暗模式
      mTbsReaderView.setForceDarkAllowed(false);
    }

targetAPI為29時(shí)

如果Android的targetSdkVersion是29的話,需要在application下面配置android:requestLegacyExternalStorage="true"

targetAPI為Android P時(shí)無(wú)法下載內(nèi)核?

由于內(nèi)核下載安裝和查詢是否可用需要向后臺(tái)發(fā)送請(qǐng)求,目前還有部分請(qǐng)求為http格式,當(dāng)targetAPI為28時(shí)非Https請(qǐng)求將會(huì)被block,會(huì)導(dǎo)致部分內(nèi)核功能異常。您可以手動(dòng)降低targetAPi到27及以下或者在您的AndroidManifst.xml中的Application標(biāo)簽中添加

android:networkSecurityConfig="@xml/network_security_config"

并在app的res/xml目錄中添加network_security_config.xml文件,文件內(nèi)容為

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true" />
</network-security-config>

由于內(nèi)核初始化需要時(shí)間,在這段時(shí)間里需要等待一會(huì)再打開文件瀏覽,否則會(huì)加載失敗。假如出現(xiàn)加載失敗,卸載重新安裝。

無(wú)法下載,或者加載不成功

    QbSdk.setTbsListener(
        new TbsListener() {
          @Override
          public void onDownloadFinish(int i) {
            //下載結(jié)束時(shí)的狀態(tài),下載成功時(shí)errorCode為100,其他均為失敗,外部不需要關(guān)注具體的失敗原因
            Log.d("QbSdk", "onDownloadFinish -->下載X5內(nèi)核完成:" + i);
          }

          @Override
          public void onInstallFinish(int i) {
            //安裝結(jié)束時(shí)的狀態(tài),安裝成功時(shí)errorCode為200,其他均為失敗,外部不需要關(guān)注具體的失敗原因
            Log.d("QbSdk", "onInstallFinish -->安裝X5內(nèi)核進(jìn)度:" + i);
          }

          @Override
          public void onDownloadProgress(int i) {
            //下載過程的通知,提供當(dāng)前下載進(jìn)度[0-100]
            Log.d("QbSdk", "onDownloadProgress -->下載X5內(nèi)核進(jìn)度:" + i);
          }
        });

上面是下載的監(jiān)聽,但是在實(shí)際中我經(jīng)常發(fā)現(xiàn)onDownloadFinish返回是110,或者120等。官網(wǎng)上注明只有100是成功。只要不是100,則X5內(nèi)核加載肯定是失敗的。但是官網(wǎng)又沒有說(shuō)如何解決。沒辦法只能自己找出路。在十分艱難閱讀了大部分帶有混淆的TBS的jar包后,連猜帶蒙的我找到了TbsDownloader.startDownload(this);這個(gè)方法??梢詫?shí)現(xiàn)重新下載,但是如果只是重新下載了還是不一定能保證x5的加載是一定成功的。所以我又找到了QbSdk.reset(this);這個(gè)方法。可以重置x5的配置。kill掉APP后就會(huì)重新下載跟初始化。在實(shí)際線上的使用情況是十分復(fù)雜的,有的人還沒等下載結(jié)束就把APPkill掉了,導(dǎo)致下載沒完成,或者是下載完成加載沒完成,所以只是使用TbsDownloader.startDownload(this);重新下載的話要結(jié)合QbSdk.setTbsListener里的回調(diào),還有QbSdk.PreInitCallback的回調(diào)來(lái)綜合判斷。

    QbSdk.PreInitCallback cb =
        new QbSdk.PreInitCallback() {
          @Override
          public void onViewInitFinished(boolean arg0) {
            // x5內(nèi)核初始化完成的回調(diào),true表x5內(nèi)核加載成功,否則表加載失敗,會(huì)自動(dòng)切換到系統(tǒng)內(nèi)核。
            Log.d("QbSdk", " 內(nèi)核加載 " + arg0);
          }

          @Override
          public void onCoreInitFinished() {
            //內(nèi)核初始化完畢
            Log.d("QbSdk", "內(nèi)核初始化完畢");
          }
        };

QbSdk.reset(this);是最好的方法,簡(jiǎn)單粗暴??梢圆榭次业膁emo,里面有我認(rèn)為比較好的解決方法。當(dāng)然還是得根據(jù)自身的需求要使用。

混淆無(wú)法使用

如果使用了混淆,則要加入以下混淆的規(guī)則

#-optimizationpasses 7
#-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-dontoptimize
-dontusemixedcaseclassnames
-verbose
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers 
-dontwarn dalvik.**
-dontwarn com.tencent.smtt.**
#-overloadaggressively

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

# Addidional for x5.sdk classes for apps

-keep class com.tencent.smtt.export.external.**{
    *;
}

-keep class com.tencent.tbs.video.interfaces.IUserStateChangedListener {
    *;
}

-keep class com.tencent.smtt.sdk.CacheManager {
    public *;
}

-keep class com.tencent.smtt.sdk.CookieManager {
    public *;
}

-keep class com.tencent.smtt.sdk.WebHistoryItem {
    public *;
}

-keep class com.tencent.smtt.sdk.WebViewDatabase {
    public *;
}

-keep class com.tencent.smtt.sdk.WebBackForwardList {
    public *;
}

-keep public class com.tencent.smtt.sdk.WebView {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebView$HitTestResult {
    public static final <fields>;
    public java.lang.String getExtra();
    public int getType();
}

-keep public class com.tencent.smtt.sdk.WebView$WebViewTransport {
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebView$PictureListener {
    public <fields>;
    public <methods>;
}


-keepattributes InnerClasses

-keep public enum com.tencent.smtt.sdk.WebSettings$** {
    *;
}

-keep public enum com.tencent.smtt.sdk.QbSdk$** {
    *;
}

-keep public class com.tencent.smtt.sdk.WebSettings {
    public *;
}


-keepattributes Signature
-keep public class com.tencent.smtt.sdk.ValueCallback {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebViewClient {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.DownloadListener {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebChromeClient {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebChromeClient$FileChooserParams {
    public <fields>;
    public <methods>;
}

-keep class com.tencent.smtt.sdk.SystemWebChromeClient{
    public *;
}
# 1. extension interfaces should be apparent
-keep public class com.tencent.smtt.export.external.extension.interfaces.* {
    public protected *;
}

# 2. interfaces should be apparent
-keep public class com.tencent.smtt.export.external.interfaces.* {
    public protected *;
}

-keep public class com.tencent.smtt.sdk.WebViewCallbackClient {
    public protected *;
}

-keep public class com.tencent.smtt.sdk.WebStorage$QuotaUpdater {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebIconDatabase {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.WebStorage {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.DownloadListener {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.QbSdk {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.QbSdk$PreInitCallback {
    public <fields>;
    public <methods>;
}
-keep public class com.tencent.smtt.sdk.CookieSyncManager {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.Tbs* {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.utils.LogFileUtils {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.utils.TbsLog {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.utils.TbsLogClient {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.CookieSyncManager {
    public <fields>;
    public <methods>;
}

# Added for game demos
-keep public class com.tencent.smtt.sdk.TBSGamePlayer {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.TBSGamePlayerClient* {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.TBSGamePlayerClientExtension {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.sdk.TBSGamePlayerService* {
    public <fields>;
    public <methods>;
}

-keep public class com.tencent.smtt.utils.Apn {
    public <fields>;
    public <methods>;
}
-keep class com.tencent.smtt.** {
    *;
}
# end


-keep public class com.tencent.smtt.export.external.extension.proxy.ProxyWebViewClientExtension {
    public <fields>;
    public <methods>;
}

-keep class MTT.ThirdAppInfoNew {
    *;
}

-keep class com.tencent.mtt.MttTraceEvent {
    *;
}

# Game related
-keep public class com.tencent.smtt.gamesdk.* {
    public protected *;
}

-keep public class com.tencent.smtt.sdk.TBSGameBooter {
        public <fields>;
        public <methods>;
}

-keep public class com.tencent.smtt.sdk.TBSGameBaseActivity {
    public protected *;
}

-keep public class com.tencent.smtt.sdk.TBSGameBaseActivityProxy {
    public protected *;
}

-keep public class com.tencent.smtt.gamesdk.internal.TBSGameServiceClient {
    public *;
}
#---------------------------------------------------------------------------


#------------------  下方是android平臺(tái)自帶的排除項(xiàng),這里不要?jiǎng)?        ----------------

-keep public class * extends android.app.Activity{
    public <fields>;
    public <methods>;
}
-keep public class * extends android.app.Application
{
    public <fields>;
    public <methods>;
}
-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 <init>(android.content.Context, android.util.AttributeSet);
}

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

-keepattributes *Annotation*

-keepclasseswithmembernames class *{
    native <methods>;
}

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

#------------------  下方是共性的排除項(xiàng)目         ----------------
# 方法名中含有“JNI”字符的,認(rèn)定是Java Native Interface方法,自動(dòng)排除
# 方法名中含有“JRI”字符的,認(rèn)定是Java Reflection Interface方法,自動(dòng)排除

-keepclasseswithmembers class * {
    ... *JNI*(...);
}

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

-keep class **JNI* {*;}


集成Demo地址

歡迎訂閱我的博客,堅(jiān)持總是會(huì)看到希望的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容