騰訊Bugly集成

首先在Module:app/build.gredle下添加依賴集成SDK

如果只想集成單獨的異常上報可以將依賴改成這樣compile 'com.tencent.bugly:crashreport:latest.release'

添加依賴.png

然后在Module:app/build.gredle下設(shè)置支持的SO庫架構(gòu)集成NDK,同時配置打開多dex

設(shè)置SO庫.png

然后仍然在在Module:app/build.gredle下設(shè)置配置簽名(當(dāng)然測試時可以不配置)霉翔,同時也在打開了混淆配置以及優(yōu)化(當(dāng)然也可以不需要配置混淆舌胶,此處配置混淆后面會提到上傳mapping快速混淆配置請參考我以前的文章

簽名并且混淆.png

然后仍然在在Module:app/build.gredle下設(shè)置配置lint檢測編譯器和運行時錯誤(當(dāng)然此處也可以不配置)贪惹,在這里我配置了多渠道打包,不配置也沒關(guān)系四康,建議配置不配置都試一下构舟,看看兩個打補丁時會有什么不同

linty以及多渠道.png

好了枫匾,下來這一點需要注意架诞,剛開始沒添加這個東西,打好補丁后一直報錯誤干茉,提示補丁版本不對如圖:

tinker.png

后面添加了這句打補丁后就可以了

gradle.project.png

好了谴忧,到這里啦異常統(tǒng)計肯定沒問題了,看看初始化

/**? ? ? ? * 單個異常上傳統(tǒng)計時的初始化方法? ? ? ? *@appContext上下文? ? ? ? *@crashReportAppId注冊時申請的APPID? ? ? ? *@isDebug自定義日志將會在Logcat中輸出角虫。? ? ? ? */CrashReport.initCrashReport(getApplicationContext(), Commont.APP_ID,false);/**? ? ? ? * 統(tǒng)一初始化Bugly產(chǎn)品沾谓,包含Beta? ? ? ? *@context上下文? ? ? ? *@appId注冊時申請的APPID? ? ? ? *@isDebug自定義日志將會在Logcat中輸出。? ? ? ? *? ? ? ? * 提示:已經(jīng)接入Bugly用戶改用上面的初始化方法,不影響原有的crash上報功能; init方法會自動檢測更新戳鹅,不需要再手動調(diào)用Beta.checkUpgrade(), 如需增加自動檢查時機可以使用Beta.checkUpgrade(false,false);? ? ? ? * 參數(shù)1:isManual 用戶手動點擊檢查均驶,非用戶點擊操作請傳false? ? ? ? * 參數(shù)2:isSilence 是否顯示彈窗等交互,[true:沒有彈窗和toast] [false:有彈窗或toast]? ? ? ? */Bugly.init(this, Commont.APP_ID,true);/**? ? ? ? * 統(tǒng)一初始化Bugly產(chǎn)品枫虏,包含Beta? ? ? ? *@context上下文? ? ? ? *@appId注冊時申請的APPID? ? ? ? *@isDebug自定義日志將會在Logcat中輸出妇穴。? ? ? ? *@strategyBugly高級設(shè)置? ? ? ? */Bugly.init(this, Commont.APP_ID,true, strategy);

上面有三種初始化的方法:

① 第一種為當(dāng)你只需要只是僅僅要使用該產(chǎn)品的異常上傳是依賴添加為上面說過的compile 'com.tencent.bugly:crashreport:latest.release',初始化時就使用第一種方法

②第二種為設(shè)置已經(jīng)用到了統(tǒng)一的初始化方法,版本也會自動檢查更新隶债,異常也會上報

③擁有了第二種方法的能力并且還有其他能力腾它,如果現(xiàn)在想添加一個App的打包渠道怎么搞,就用到了最后一個參數(shù)strategy作為Bugly高級設(shè)置死讹。瞒滴。。

到這里了赞警,可以說應(yīng)用升級也基本已經(jīng)完成了妓忍,我們在到Manifest里面為升級補全配置

<!-- bugly配置權(quán)限start --><!-- bugly配置權(quán)限end --><!-- Bugly升級SDK配置開始 --><!-- 想兼容Android N或者以上的設(shè)備 --><!--友盟 Appkey 自己應(yīng)用注冊申請來的--><!--渠道號,多渠道這里使用了占位符$-->

在res文件下創(chuàng)建新文件xml并創(chuàng)建文件provider_paths.xml

<?xml version="1.0"encoding="utf-8"?><!-- 這里配置的兩個外部存儲路徑是升級SDK下載的文件可能存在的路徑 --><!-- /storage/emulated/0/Download/com.bugly.upgrade.demo/.beta/apk--><!--/storage/emulated/0/Android/data/com.bugly.upgrade.demo/files/apk/-->

ok愧旦,升級也完成了世剖, 看看最后打補丁-----熱修復(fù)

我這里用到了第三方的一個插件,方便簡單一點忘瓦,我們首先去下載一個插件Bugly

AbdroidStudio插件下載.png

完了之后就再根目錄下創(chuàng)建一個tinker-support.gradle,然后再配置里面的東西

tinker-support.gradle.png

詳細配置:

apply plugin:'com.tencent.bugly.tinker-support'def bakPath = file("${buildDir}/bakApk/")/** * 此處填寫每次構(gòu)建生成的基準包目錄 */def baseApkDir ="app-0119-10-02-31"/** * 對于插件各參數(shù)的詳細解析請參考 */tinkerSupport {? ? // 開啟tinker-support插件搁廓,默認值trueenable=true// tinkerEnable功能開關(guān)? ? tinkerEnable =true// 是否編譯完成后引颈,歸檔apk到指定目錄,默認值false// 指定歸檔目錄境蜕,默認值當(dāng)前module的子目錄tinker? ? autoBackupApkDir ="${bakPath}"http:// 是否啟用覆蓋tinkerPatch配置功能蝙场,默認值false// 開啟后tinkerPatch配置不生效,即無需添加tinkerPatch? ? overrideTinkerPatchConfiguration =true// 編譯補丁包時粱年,必需指定基線版本的apk售滤,默認值為空? ? // 如果為空,則表示不是進行補丁包的編譯? ? // @{link tinkerPatch.oldApk }? ? baseApk ="${bakPath}/${baseApkDir}/app-release.apk"http:// 對應(yīng)tinker插件applyMapping? ? baseApkProguardMapping ="${bakPath}/${baseApkDir}/app-release-mapping.txt"http:// 對應(yīng)tinker插件applyResourceMapping? ? baseApkResourceMapping ="${bakPath}/${baseApkDir}/app-release-R.txt"http:// 構(gòu)建基準包和補丁包都要指定不同的tinkerId台诗,并且必須保證唯一性//? ? tinkerId ="1.0.0.4-base"http://生成對于的基包版本? 只有生成基準包的時候使用? ? tinkerId ="1.0.0.4-patch"http://對于生成的補丁包版本? 只有生成補丁包的時候使用? ? // 構(gòu)建多渠道補丁時使用? ? buildAllFlavorsDir ="${bakPath}/${baseApkDir}"http:// 是否啟用加固模式完箩,默認為false.(tinker-spport 1.0.7起支持)? ? // isProtectedApp =true// 是否開啟反射Application模式? ? enableProxyApplication =false// 是否支持新增非export的Activity(注意:設(shè)置為true才能修改AndroidManifest文件)? ? supportHotplugComponent =true}/** * 一般來說,我們無需對下面的參數(shù)做任何的修改 * 對于各參數(shù)的詳細介紹請參考: * https://github.com/Tencent/tinker/wiki/Tinker-%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97 */tinkerPatch {? ? tinkerEnable =true//oldApk ="${bakPath}/${appName}/app-release.apk"ignoreWarning =false//對應(yīng)tinker插件userSign, 在運行過程中,? ? // 我們需要驗證基準apk包與補丁包的簽名是否一致拉队,我們是否需要為你簽名弊知。? ? useSign =truedex {? ? ? ? dexMode ="jar"pattern = ["classes*.dex"]? ? ? ? loader = []? ? }? ? lib {? ? ? ? pattern = ["lib/*/*.so"]? ? }? ? res {? ? ? ? pattern = ["res/*","r/*","assets/*","resources.arsc","AndroidManifest.xml"]? ? ? ? ignoreChange = []? ? ? ? largeModSize = 100? ? }? ? // 用于生成補丁包中的'package_meta.txt'文件? ? packageConfig {//? ? ? ? configField("patchMessage","tinker is sample to use")//? ? ? ? configField("platform","all")//? ? ? ? configField("patchVersion","1.0.5")? ? }? ? sevenZip {? ? ? ? zipArtifact ="com.tencent.mm:SevenZip:1.1.10"http://? ? ? ? path ="/usr/local/bin/7za"}? ? buildConfig {? ? ? ? keepDexApply =false//tinkerId ="1.0.1-base"http://applyMapping ="${bakPath}/${appName}/app-release-mapping.txt"http://? 可選,設(shè)置mapping文件粱快,建議保持舊apk的proguard混淆方式? ? ? ? //applyResourceMapping ="${bakPath}/${appName}/app-release-R.txt"http:// 可選秩彤,設(shè)置R.txt文件,通過舊apk文件保持ResId的分配? ? }}

在上述代碼中tinkerSupport{}里面有這樣一句事哭,很清楚漫雷,如果你的項目沒有用到多渠道打包,那么你可以將這一句注釋掉鳍咱,不用管它

構(gòu)建渠道補丁.png

還有這樣一句代碼:

構(gòu)建渠道補丁.png

這種情況下分為兩種降盹,enableProxyApplication默認為false

當(dāng)enableProxyApplication為false時

① 新建SampleApplicationLike繼承于DefaultApplicationLike,實現(xiàn)構(gòu)造方法谤辜,在將Application中所有要執(zhí)行的操作復(fù)制到這個類中

② 新建SampleApplication集成于TinkerApplication,構(gòu)造這樣寫

publicSampleApplication(){//記住此處com.suchengkeji.android.bugly.applications.SampleApplicationLike改為你自己新建的路徑包名super(ShareConstants.TINKER_ENABLE_ALL,"com.suchengkeji.android.bugly.applications.SampleApplicationLike","com.tencent.tinker.loader.TinkerLoader",false);? ? }@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)@OverridepublicvoidonBaseContextAttached(Context base){super.onBaseContextAttached(base);// you must install multiDex whatever tinker is installed!MultiDex.install(base);// 安裝tinker// TinkerManager.installTinker(this); 替換成下面Bugly提供的方法Beta.installTinker(this);? ? }@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)publicvoidregisterActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks){? ? ? ? getApplication().registerActivityLifecycleCallbacks(callbacks);? ? }

③ 將啟動Application改為SampleApplication

manifest.png

當(dāng)enableProxyApplication為true時

① 自定義自己的Application為MyApplication蓄坏,將所有要初始化的操作都寫在MyApplication中,當(dāng)然為了以防萬一將初始化操作做到極致丑念,將補丁安裝和多dex在attachBaseContext方法中就開始初始化

@OverrideprotectedvoidattachBaseContext(Context base){super.attachBaseContext(base);// you must install multiDex whatever tinker is installed!MultiDex.install(base);// 安裝tinker// TinkerManager.installTinker(this); 替換成下面Bugly提供的方法Beta.installTinker(this);? ? }

② 在onCreate()方法中可初始化設(shè)置Bugly一些鬼

這里額外說下Application啟動時流程: attachBaseContext(Context) -----> onCreate()

③ 'Applaction'啟動項改回來剑辫,改為我們自定義的

manifest2.png

到這里也就接近完了,現(xiàn)在看看怎么創(chuàng)建基準包和補丁包

如果我們現(xiàn)在要上線一個App為了以防萬一的突發(fā)bug要創(chuàng)建一個基準包上線渠欺,以防有bug即使熱修復(fù)

① 首先在Module:app/build.gradle中引入我們?yōu)闊嵝迯?fù)配置好的腳本插件

依賴插件腳本.png

② 現(xiàn)在就可以按照下圖生成基準包了,圖中1生成的為沒有渠道的椎眯,2很明顯是一個渠道挠将,為騰訊應(yīng)用寶的渠道,根據(jù)自己情況生成基準包

基準包生成.png

看看生成后的目錄编整,其中下面框中的三個中的兩個在上傳基準包和生成補丁包時要用到舔稀,上傳在后面,先把打補丁說了

基準包.png

如果我們的App發(fā)現(xiàn)了bug我們現(xiàn)在需要打補丁

補丁包1.png

補丁包2.png

看看打補丁后生成的目錄掌测,最后生成的7zip.apk就是要上傳的補丁包

補丁包.png

基準包内贮、mapping以及補丁包的上傳

進入官網(wǎng)登陸,沒有項目的可以新建

新建.png

復(fù)制App ID在我們的項目中配置

APPID.png

后面的直接上圖了:

我們生成的基準包

啟動

補丁的發(fā)布

image.png

如果你的應(yīng)用再次全量更新,可以撤回和停止補丁的下發(fā)

image.png

mapping的上傳

為什么要上傳mapping?

mapping是你在項目中配置了混淆時才會有的東西夜郁,主要是為了對比編譯前后方法名等一些量的混淆什燕,能更方便的調(diào)試代碼,定位錯誤位置

image.png

最后貼出以本Demo為例的源碼

MyApplication

publicclassMyApplicationextendsApplication{@OverrideprotectedvoidattachBaseContext(Context base){? ? ? ? super.attachBaseContext(base);// you must install multiDex whatever tinker is installed!MultiDex.install(base);// 安裝tinker// TinkerManager.installTinker(this); 替換成下面Bugly提供的方法Beta.installTinker(this);? ? }? ? @OverridepublicvoidonCreate(){? ? ? ? super.onCreate();? ? ? ? setBugly();? ? }privatevoidsetBugly(){/***** Beta高級設(shè)置 *****//**

? ? ? ? * true表示app啟動自動初始化升級模塊; false不會自動初始化;

? ? ? ? * 開發(fā)者如果擔(dān)心sdk初始化影響app啟動速度竞端,可以設(shè)置為false屎即,

? ? ? ? * 在后面某個時刻手動調(diào)用Beta.init(getApplicationContext(),false);

? ? ? ? */Beta.autoInit =true;/**

? ? ? ? * true表示初始化時自動檢查升級; false表示不會自動檢查升級,需要手動調(diào)用Beta.checkUpgrade()方法;

? ? ? ? */Beta.autoCheckUpgrade =true;/**

? ? ? ? * 設(shè)置升級檢查周期為60s(默認檢查周期為0s),60s內(nèi)SDK不重復(fù)向后臺請求策略);

? ? ? ? */Beta.upgradeCheckPeriod =60*1000;/**

? ? ? ? * 設(shè)置啟動延時為1s(默認延時3s)事富,APP啟動1s后初始化SDK技俐,避免影響APP啟動速度;

? ? ? ? */Beta.initDelay =1*1000;/**

? ? ? ? * 設(shè)置通知欄大圖標(biāo),largeIconId為項目中的圖片資源;

? ? ? ? */Beta.largeIconId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置狀態(tài)欄小圖標(biāo)统台,smallIconId為項目中的圖片資源Id;

? ? ? ? */Beta.smallIconId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置更新彈窗默認展示的banner雕擂,defaultBannerId為項目中的圖片資源Id;

? ? ? ? * 當(dāng)后臺配置的banner拉取失敗時顯示此banner,默認不設(shè)置則展示“l(fā)oading“;

? ? ? ? */Beta.defaultBannerId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置sd卡的Download為更新資源保存目錄;

? ? ? ? * 后續(xù)更新資源會保存在此目錄贱勃,需要在manifest中添加WRITE_EXTERNAL_STORAGE權(quán)限;

? ? ? ? */Beta.storageDir = Environment? ? ? ? ? ? ? ? .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);/**

? ? ? ? * 已經(jīng)確認過的彈窗在APP下次啟動自動檢查更新時會再次顯示;

? ? ? ? */Beta.showInterruptedStrategy =true;/**

? ? ? ? * 只允許在MainActivity上顯示更新彈窗井赌,其他activity上不顯示彈窗; 不設(shè)置會默認所有activity都可以顯示彈窗;

? ? ? ? */Beta.canShowUpgradeActs.add(MainActivity.class);/***** Bugly高級設(shè)置 *****/BuglyStrategy strategy =newBuglyStrategy();/**

? ? ? ? * 設(shè)置app渠道號

? ? ? ? */strategy.setAppChannel(ChannelUtils.getAppMetaData(this,"UMENG_CHANNEL"));//? ? ? ? /**//? ? ? ? * 單個異常上傳統(tǒng)計時的初始化方法//? ? ? ? * @appContext 上下文//? ? ? ? * @crashReportAppId 注冊時申請的APPID//? ? ? ? * @isDebug 自定義日志將會在Logcat中輸出。//? ? ? ? *///? ? ? ? CrashReport.initCrashReport(getApplicationContext(), Commont.APP_ID, false);////? ? ? ? /**//? ? ? ? * 統(tǒng)一初始化Bugly產(chǎn)品募寨,包含Beta//? ? ? ? * @context 上下文//? ? ? ? * @appId 注冊時申請的APPID//? ? ? ? * @isDebug 自定義日志將會在Logcat中輸出族展。//? ? ? ? *//? ? ? ? * 提示:已經(jīng)接入Bugly用戶改用上面的初始化方法,不影響原有的crash上報功能; init方法會自動檢測更新,不需要再手動調(diào)用Beta.checkUpgrade(), 如需增加自動檢查時機可以使用Beta.checkUpgrade(false,false);//? ? ? ? * 參數(shù)1:isManual 用戶手動點擊檢查拔鹰,非用戶點擊操作請傳false//? ? ? ? * 參數(shù)2:isSilence 是否顯示彈窗等交互仪缸,[true:沒有彈窗和toast] [false:有彈窗或toast]//? ? ? ? *///? ? ? ? Bugly.init(this, Commont.APP_ID, true);/**

? ? ? ? * 統(tǒng)一初始化Bugly產(chǎn)品,包含Beta

? ? ? ? * @context 上下文

? ? ? ? * @appId 注冊時申請的APPID

? ? ? ? * @isDebug 自定義日志將會在Logcat中輸出列肢。

? ? ? ? * @strategy Bugly高級設(shè)置

? ? ? ? */Bugly.init(this, Commont.APP_ID,true, strategy);? ? }}

SampleApplication

/**

* 注意:這個類集成TinkerApplication類恰画,這里面不做任何操作,所有Application的代碼都會放到ApplicationLike繼承類當(dāng)中

* 參數(shù)解析

* 參數(shù)1:tinkerFlags 表示Tinker支持的類型 dex only瓷马、library only or all suuport拴还,default: TINKER_ENABLE_ALL

* 參數(shù)2:delegateClassName Application代理類 這里填寫你自定義的ApplicationLike

* 參數(shù)3:loaderClassName Tinker的加載器,使用默認即可

* 參數(shù)4:tinkerLoadVerifyFlag 加載dex或者lib是否驗證md5欧聘,默認為false

*/publicclassSampleApplicationextendsTinkerApplication{publicSampleApplication(){//將‘com.suchengkeji.android.bugly.applications.SampleApplicationLike’替換為自己的包名及路徑super(ShareConstants.TINKER_ENABLE_ALL,"com.suchengkeji.android.bugly.applications.SampleApplicationLike","com.tencent.tinker.loader.TinkerLoader",false);? ? }}

SampleApplicationLike

publicclassSampleApplicationLikeextendsDefaultApplicationLike{publicSampleApplicationLike(Application application,inttinkerFlags,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? boolean tinkerLoadVerifyFlag,longapplicationStartElapsedTime,longapplicationStartMillisTime, Intent tinkerResultIntent){? ? ? ? super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);? ? }? ? @OverridepublicvoidonCreate(){? ? ? ? super.onCreate();// 這里實現(xiàn)SDK初始化片林,appId替換成你的在Bugly平臺申請的appId// 調(diào)試時,將第三個參數(shù)改為true//? ? ? ? Bugly.init(getApplication(), APP_ID, false);setBUG();? ? }privatevoidsetBUG(){/***** Beta高級設(shè)置 *****//**

? ? ? ? * true表示app啟動自動初始化升級模塊; false不會自動初始化;

? ? ? ? * 開發(fā)者如果擔(dān)心sdk初始化影響app啟動速度怀骤,可以設(shè)置為false费封,

? ? ? ? * 在后面某個時刻手動調(diào)用Beta.init(getApplicationContext(),false);

? ? ? ? */Beta.autoInit =true;/**

? ? ? ? * true表示初始化時自動檢查升級; false表示不會自動檢查升級,需要手動調(diào)用Beta.checkUpgrade()方法;

? ? ? ? */Beta.autoCheckUpgrade =true;/**

? ? ? ? * 設(shè)置升級檢查周期為60s(默認檢查周期為0s),60s內(nèi)SDK不重復(fù)向后臺請求策略);

? ? ? ? */Beta.upgradeCheckPeriod =60*1000;/**

? ? ? ? * 設(shè)置啟動延時為1s(默認延時3s)蒋伦,APP啟動1s后初始化SDK弓摘,避免影響APP啟動速度;

? ? ? ? */Beta.initDelay =1*1000;/**

? ? ? ? * 設(shè)置通知欄大圖標(biāo),largeIconId為項目中的圖片資源;

? ? ? ? */Beta.largeIconId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置狀態(tài)欄小圖標(biāo)痕届,smallIconId為項目中的圖片資源Id;

? ? ? ? */Beta.smallIconId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置更新彈窗默認展示的banner韧献,defaultBannerId為項目中的圖片資源Id;

? ? ? ? * 當(dāng)后臺配置的banner拉取失敗時顯示此banner末患,默認不設(shè)置則展示“l(fā)oading“;

? ? ? ? */Beta.defaultBannerId = R.mipmap.ic_launcher;/**

? ? ? ? * 設(shè)置sd卡的Download為更新資源保存目錄;

? ? ? ? * 后續(xù)更新資源會保存在此目錄,需要在manifest中添加WRITE_EXTERNAL_STORAGE權(quán)限;

? ? ? ? */Beta.storageDir = Environment? ? ? ? ? ? ? ? .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);/**

? ? ? ? * 已經(jīng)確認過的彈窗在APP下次啟動自動檢查更新時會再次顯示;

? ? ? ? */Beta.showInterruptedStrategy =true;/**

? ? ? ? * 只允許在MainActivity上顯示更新彈窗锤窑,其他activity上不顯示彈窗; 不設(shè)置會默認所有activity都可以顯示彈窗;

? ? ? ? */Beta.canShowUpgradeActs.add(MainActivity.class);/***** Bugly高級設(shè)置 *****/BuglyStrategy strategy =newBuglyStrategy();/**

? ? ? ? * 設(shè)置app渠道號

? ? ? ? * ChannelUtils.getAppMetaData(this, "UMENG_CHANNEL")獲取渠道號

? ? ? ? */strategy.setAppChannel(ChannelUtils.getAppMetaData(getApplication(),"UMENG_CHANNEL"));/***** 統(tǒng)一初始化Bugly產(chǎn)品璧针,包含Beta *****/Bugly.init(getApplication(), Commont.APP_ID,true, strategy);? ? }? ? @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)? ? @OverridepublicvoidonBaseContextAttached(Context base){? ? ? ? super.onBaseContextAttached(base);// you must install multiDex whatever tinker is installed!MultiDex.install(base);// 安裝tinker// TinkerManager.installTinker(this); 替換成下面Bugly提供的方法Beta.installTinker(this);? ? }? ? @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)publicvoidregisterActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks){? ? ? ? getApplication().registerActivityLifecycleCallbacks(callbacks);? ? }}

MainActivity

publicclassMainActivityextendsAppCompatActivityimplementsAdapterView.OnItemClickListener{@BindView(R.id.list_view)? ? ListView listView;? ? String[] strings = {"異常上報","應(yīng)用更新","熱修復(fù)測試"};@OverrideprotectedvoidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);? ? ? ? setContentView(R.layout.activity_main);? ? ? ? ButterKnife.bind(this);? ? ? ? setList();? ? }privatevoidsetList(){? ? ? ? listView.setAdapter(newBaseAdapter() {@OverridepublicintgetCount(){returnstrings.length;? ? ? ? ? ? }@OverridepublicObjectgetItem(intposition){returnstrings[position];? ? ? ? ? ? }@OverridepubliclonggetItemId(intposition){returnposition;? ? ? ? ? ? }@OverridepublicViewgetView(intposition, View convertView, ViewGroup parent){@SuppressLint("ViewHolder") View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.list_item, parent,false);? ? ? ? ? ? ? ? TextView textView = (TextView) view.findViewById(R.id.list_item_text);? ? ? ? ? ? ? ? textView.setText(strings[position]);returnview;? ? ? ? ? ? }? ? ? ? });? ? ? ? listView.setOnItemClickListener(this);? ? }@OverridepublicvoidonItemClick(AdapterView parent, View view,intposition,longid){? ? ? ? Log.d(LogUtils.TAG(), position +"");switch(position) {case0:/***** 異常崩潰上傳 *****/CrashReport.testJavaCrash();break;case1:/***** 檢查更新 *****/loadUpgradeInfo();? ? ? ? ? ? ? ? loadAppInfo();? ? ? ? ? ? ? ? Beta.checkUpgrade();break;case2:/***** 崩潰上傳(此處要打修復(fù)補丁) *****/FixBugClass.getTimer(MainActivity.this);//? ? ? ? ? ? ? ? BugClass.getTimer(MainActivity.this);break;? ? ? ? }? ? }@OverrideprotectedvoidonStart(){super.onStart();//添加權(quán)限PermissionGen.with(this)? ? ? ? ? ? ? ? .addRequestCode(Commont.PHOTO_PERMISS)? ? ? ? ? ? ? ? .permissions(? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.INTERNET,? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.READ_PHONE_STATE,? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.ACCESS_NETWORK_STATE,? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.ACCESS_WIFI_STATE,? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.READ_LOGS,? ? ? ? ? ? ? ? ? ? ? ? Manifest.permission.WRITE_EXTERNAL_STORAGE)? ? ? ? ? ? ? ? .request();? ? }@PermissionSuccess(requestCode = Commont.PHOTO_PERMISS)publicvoidrequestPhotoSuccess(){//成功之后的處理//.......Log.d(LogUtils.TAG(),"動態(tài)權(quán)限加載成功");? ? }@PermissionFail(requestCode = Commont.PHOTO_PERMISS)publicvoidrequestPhotoFail(){//失敗之后的處理果复,我一般是跳到設(shè)置界面Log.d(LogUtils.TAG(),"動態(tài)權(quán)限加載失敗");? ? }/**

? ? * 獲取升級信息

? ? */privatevoidloadUpgradeInfo(){/***** 獲取升級信息 *****/UpgradeInfo upgradeInfo = Beta.getUpgradeInfo();if(upgradeInfo ==null) {? ? ? ? ? ? Log.d(LogUtils.TAG(),"無升級信息");return;? ? ? ? }? ? ? ? StringBuilder info =newStringBuilder();? ? ? ? info.append("id: ").append(upgradeInfo.id).append("\n");? ? ? ? info.append("標(biāo)題: ").append(upgradeInfo.title).append("\n");? ? ? ? info.append("升級說明: ").append(upgradeInfo.newFeature).append("\n");? ? ? ? info.append("versionCode: ").append(upgradeInfo.versionCode).append("\n");? ? ? ? info.append("versionName: ").append(upgradeInfo.versionName).append("\n");? ? ? ? info.append("發(fā)布時間: ").append(upgradeInfo.publishTime).append("\n");? ? ? ? info.append("安裝包Md5: ").append(upgradeInfo.apkMd5).append("\n");? ? ? ? info.append("安裝包下載地址: ").append(upgradeInfo.apkUrl).append("\n");? ? ? ? info.append("安裝包大小: ").append(upgradeInfo.fileSize).append("\n");? ? ? ? info.append("彈窗間隔(ms): ").append(upgradeInfo.popInterval).append("\n");? ? ? ? info.append("彈窗次數(shù): ").append(upgradeInfo.popTimes).append("\n");? ? ? ? info.append("發(fā)布類型(0:測試 1:正式): ").append(upgradeInfo.publishType).append("\n");? ? ? ? info.append("彈窗類型(1:建議 2:強制 3:手工): ").append(upgradeInfo.upgradeType);? ? ? ? Log.d(LogUtils.TAG(), info +"");? ? }privatevoidloadAppInfo(){try{? ? ? ? ? ? StringBuilder info =newStringBuilder();? ? ? ? ? ? PackageInfo packageInfo =this.getPackageManager().getPackageInfo(this.getPackageName(),? ? ? ? ? ? ? ? ? ? ? ? ? ? PackageManager.GET_CONFIGURATIONS);intversionCode = packageInfo.versionCode;? ? ? ? ? ? String versionName = packageInfo.versionName;? ? ? ? ? ? info.append("appid: ").append(Commont.APP_ID).append(" ")? ? ? ? ? ? ? ? ? ? .append("channel: ")? ? ? ? ? ? ? ? ? ? .append(ChannelUtils.getAppMetaData(MainActivity.this,"UMENG_CHANNEL"))? ? ? ? ? ? ? ? ? ? .append(" ")? ? ? ? ? ? ? ? ? ? .append("version: ").append(versionName).append(".").append(versionCode);? ? ? ? ? ? Log.d(LogUtils.TAG(), info +"");? ? ? ? }catch(Exception e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }}

Commont

publicclassCommont{/***? 騰訊Bugly產(chǎn)品ID? ***/publicstaticfinalString APP_ID ="5e****70c08";/***? 權(quán)限處理標(biāo)識? ***/publicstaticfinalint PHOTO_PERMISS =100;}

ChannelUtils

/**

? ? * 獲取app當(dāng)前的渠道號或application中指定的meta-data

? ? *

? ? * @return 如果沒有獲取成功(沒有對應(yīng)值陈莽,或者異常),則返回值為空

? ? */publicstaticStringgetAppMetaData(Context context,Stringkey) {if(context ==null|| TextUtils.isEmpty(key)) {returnnull;? ? ? ? }StringchannelNumber =null;try{? ? ? ? ? ? PackageManager packageManager = context.getPackageManager();if(packageManager !=null) {? ? ? ? ? ? ? ? ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);if(applicationInfo !=null) {if(applicationInfo.metaData !=null) {? ? ? ? ? ? ? ? ? ? ? ? channelNumber = applicationInfo.metaData.getString(key);? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? }catch(PackageManager.NameNotFoundException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }returnchannelNumber;? ? }//? ? ? 在需要的地方調(diào)用//? ? String channelNumber = getAppMetaData(getBaseContext(), "UMENG_CHANNEL");//獲取app當(dāng)前的渠道號}

BugClass

/**

* 有錯誤的bug類

*/publicclassBugClass{privatestaticString timeType ="yyyy-MM-dd HH:mm:ss";publicstaticvoidgetTimer(Context c){? ? ? ? String date =null;? ? ? ? Log.d(LogUtils.TAG(),"上線后的緊急BUG");? ? ? ? Log.d(LogUtils.TAG(), date.length() +"");//此處留一個空指針bug@SuppressLint("SimpleDateFormat")? ? ? ? SimpleDateFormat sDateFormat =newSimpleDateFormat(timeType);? ? ? ? date = sDateFormat.format(newjava.util.Date());? ? ? ? Toast.makeText(c, date, Toast.LENGTH_SHORT).show();? ? }}

FixBugClass

/**

* 修復(fù)過bug的補丁類

*/publicclassFixBugClass{privatestaticString timeType ="yyyy-MM-dd HH:mm:ss";publicstaticvoidgetTimer(Context c){? ? ? ? String date =null;? ? ? ? Log.d(LogUtils.TAG(),"上線后的緊急BUG修復(fù)補丁");//Log.d(LogUtils.TAG(), date.length() + "");//去掉此處的bug@SuppressLint("SimpleDateFormat")? ? ? ? SimpleDateFormat sDateFormat =newSimpleDateFormat(timeType);? ? ? ? date = sDateFormat.format(newjava.util.Date());? ? ? ? Toast.makeText(c, date, Toast.LENGTH_SHORT).show();? ? }}

注意點虽抄,打完補丁之后在運行應(yīng)用是走搁,第一次仍然會崩潰,不過在崩潰時會自己打補丁修復(fù)迈窟,第二次以后就好了

好了私植,到這里就完了,此文章僅供參考车酣,具體以官方文檔為準,有更好的思路或方法曲稼,請不吝告知,如有錯誤湖员,請及時指出贫悄。。

作者:一s獨秀

鏈接:http://www.reibang.com/p/fbab774dab8e

來源:簡書

簡書著作權(quán)歸作者所有娘摔,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處窄坦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市凳寺,隨后出現(xiàn)的幾起案子鸭津,更是在濱河造成了極大的恐慌,老刑警劉巖肠缨,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逆趋,死亡現(xiàn)場離奇詭異,居然都是意外死亡晒奕,警方通過查閱死者的電腦和手機闻书,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脑慧,“玉大人惠窄,你說我怎么就攤上這事⊙龋” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵楞卡,是天一觀的道長霜运。 經(jīng)常有香客問我脾歇,道長,這世上最難降的妖魔是什么淘捡? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任藕各,我火速辦了婚禮,結(jié)果婚禮上焦除,老公的妹妹穿的比我還像新娘激况。我一直安慰自己,他們只是感情好膘魄,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布乌逐。 她就那樣靜靜地躺著,像睡著了一般创葡。 火紅的嫁衣襯著肌膚如雪浙踢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天灿渴,我揣著相機與錄音洛波,去河邊找鬼。 笑死骚露,一個胖子當(dāng)著我的面吹牛蹬挤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棘幸,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼焰扳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了够话?” 一聲冷哼從身側(cè)響起蓝翰,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎女嘲,沒想到半個月后畜份,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡欣尼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年爆雹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愕鼓。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡钙态,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菇晃,到底是詐尸還是另有隱情册倒,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布磺送,位于F島的核電站驻子,受9級特大地震影響灿意,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崇呵,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一缤剧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧域慷,春花似錦荒辕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至化漆,卻和暖如春估脆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背座云。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工疙赠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朦拖。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓圃阳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親璧帝。 傳聞我的和親對象是個殘疾皇子捍岳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 簡單的記錄下在快速集成Bugly是遇到過的坑,更多說明去官方文檔睬隶,此文章锣夹,簡單的集成bugly實現(xiàn)了,異常統(tǒng)計苏潜,應(yīng)...
    一s獨秀閱讀 16,653評論 12 17
  • 前言 熱更新能力是Bugly為解決開發(fā)者緊急修復(fù)線上bug银萍,而無需重新發(fā)版讓用戶無感知就能把問題修復(fù)的一項能力。B...
    Smile__EveryDay閱讀 24,856評論 31 19
  • Bugly Android熱更新使用指南前言:在項目進行的時候恤左,因為可能上線項目存在bug贴唇,影響用戶的體驗。所以不...
    蒲小帥丶閱讀 1,632評論 2 19
  • 前言 熱更新能力是Bugly為解決開發(fā)者緊急修復(fù)線上bug飞袋,而無需重新發(fā)版讓用戶無感知就能把問題修復(fù)的一項能力戳气。目...
    LnJan閱讀 1,807評論 2 3
  • 一、官方文檔 首先巧鸭,官方文檔瓶您,官方文檔,官方文檔!Bugly Android熱更新 二览闰、個人總結(jié) 1.配置Appl...
    無_理閱讀 1,409評論 0 1