序言
騰訊瀏覽服務(wù)功能強(qiáng)大,穩(wěn)定,集成還算是比較簡(jiǎn)單的,比原生的webview強(qiáng)。最主要的是可以瀏覽PDF,Word文檔,方便不少。此篇文章主要不是在講集成,雖然集成的篇幅多些,但是我寫的最重要的目的是我在實(shí)際使用過程中碰到的問題,以及解決方案。如果已經(jīng)成功集成的了,可直接看其他問題,可能會(huì)有你想要的。
基本上的話照著這個(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聲明
- 在AndroidManifest.xml中增加內(nèi)核首次加載時(shí)優(yōu)化Service聲明。
- 該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)起 miniqb 的 Activity 的 context。此參數(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* {*;}
歡迎訂閱我的博客,堅(jiān)持總是會(huì)看到希望的。