Ⅰ 【android】Permission denied (missing INTERNET permission)異常踩坑
自己在做項目的時候,發現APK在某廠家的一款機頂盒上開機啟動的時候,接收開機廣播拉起進程之後,進程突然崩潰,如果再次拉起進程,又能夠正常前納使用了,經過全局異常捕獲發現,導致進程崩潰的原因居然是okhttp中拋出的一個異常:
第一眼看這個異常,肯定會想到,這特么的是沒有加許可權啊!!!然而事情如果有這么簡單的話,還填個毛的坑啊!!!接下來,講一下關於這個異常的情況。
對於這種異常,大部分情況下確實因為沒有添加網路許可權導致的,一般只需要添加
<uses-permission android:name="android.permission.INTERNET" />
該許可權即可解決該異常引起的崩潰,然後我再項目中查了一遍又一遍,確認了一次又一次,確定不是由於未添加網路許可權導致的該異常,難道還有其他原因?
查看了出現該異常的其他博客,也有人在孝腔出現該異常時添加如下許可權就解決了的
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
事實上,依然沒有效果,開機該崩潰還得崩潰;後來在想乾脆將網路許可權都加上,流氓點就流巧悔衫氓點,但該總不會導致這個異常了吧?
爽不過三秒,開啟重啟,還是崩潰了~~~~~~~
因為做大屏應用開發,很多應用需要在開機之後就要後台運行,如果開機進程掛了不能起來就玩完了。查了很多資料,目前尚不明確具體什麼原因導致的該異常,初步定位為與ROM有關,但事情總得想法子解決的。如何解決?
既然是okHttp網路訪問出現的異常導致的崩潰,那麼我這邊想法是通過okHttp攔截器來攔截該異常,並做相關處理。具體的攔截器寫法如下:
所以我這里就是先搞一個定時器,10秒後定時發送廣播,拉起自己,同時手動kill掉進程,這樣既保證了崩潰平台不會大批量收集該異常,同時進程保證也能夠正常再開機的時候運行,雖然kill了一次,但不影響業務,至此,雖然沒找到具體的原因,但還是解決了該問題。
如果有哪位在使用oKhttop的時候也出現了這類異常,並且不是由於簡單的許可權問題導致的,分析到了原因還望告知,謝謝。
同步發布於掘金: https://juejin.im/post/5b129d295188257d86687532
Ⅱ android全局捕獲異常使用詳解
2.2: 在自己程序中BaseApplication中的onCreate()方法設置全局異常捕捉類
2.3:直接在MainActivity的initData()初始化數據方法中隱者,獲取上次崩潰灶乎薯信息,然後列印即可
以上就是全局頃隱異常捕獲及使用步驟,如若需要,直接拷貝到自己項目中即可使用
地址如下
https://www.jianshu.com/u/c5fabe27176e
Ⅲ Android 捕獲全局異常CrashHandler,防止異常閃退,記錄異常日誌
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* UncaughtException handler class
*
*/
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler";
public static final String PROGRAM_BROKEN_ACTION = "com.teligen.wccp.PROGRAM_BROKEN";
private UncaughtExceptionHandler mDefaultHandler;
private static CrashHandler instance = new CrashHandler();
private Context mContext;
private Class<?> mainActivityClass;
private Map<String, String> infos = new HashMap<String, String>();
private CrashHandler() {
}
public static CrashHandler getInstance() {
return instance;
}
public void init(Context context, Class<?> activityClass) {
mContext = context;
this.setMainActivityClass(activityClass);
mDefaultHandler = Thread.();
Thread.(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
System.out.println("uncaughtException--->" + ex.getMessage());
// Log.e(TAG, ex.getMessage());
logError(ex);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// Log.e("debug", "error:", e);
}
exitApp();
}
}
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext.getApplicationContext(),
"unknown exception and exiting...Please checking logs in sd card!", Toast.LENGTH_LONG).show();
Looper.loop();
}
}).start();
collectDeviceInfo(mContext.getApplicationContext());
logError(ex);
return true;
}
private void exitApp() {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
public void collectDeviceInfo(Context ctx) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
PackageManager.GET_ACTIVITIES);
if (pi != null) {
String versionName = pi.versionName == null ? "null"
: pi.versionName;
String versionCode = pi.versionCode + "";
infos.put("versionName", versionName);
infos.put("versionCode", versionCode);
}
} catch (NameNotFoundException e) {
e.printStackTrace();
}
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
infos.put(field.getName(), field.get(null).toString());
} catch (Exception e) {
}
}
}
private void logError(Throwable ex) {
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, String> entry : infos.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key + "=" + value + "\n");
}
int num = ex.getStackTrace().length;
for (int i=0;i<num;i++){
sb.append(ex.getStackTrace()[i].toString());
sb.append("\n");
}
File file = new File(filePath+"/log.txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
fos.write((sb.toString()+"exception:"+ex.getLocalizedMessage()).getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public Class<?> getMainActivityClass() {
return mainActivityClass;
}
public void setMainActivityClass(Class<?> mainActivityClass) {
this.mainActivityClass = mainActivityClass;
}
}
filePath是記錄日誌的路徑
在Applicaton中初始化
@Override
public void onCreate() {
super.onCreate();
CrashHandler mCrashHandler = CrashHandler.getInstance();
mCrashHandler.init(getApplicationContext(), getClass());
initFile();
}
Ⅳ android 捕獲系統異常並上傳日誌的實例
在做項目時,經常會把錯誤利用異常拋出去,這樣在開發時就可以通過手機拋出的異常排查錯誤。但是當程序開發完畢,版本穩定,需要上線時,為了避免拋出異常影響用戶感受,可以用UncaughtExceptionHandler捕獲全局異常,對異常做出處理。比如我們可以獲取到拋出異常的時間、手機的硬體信息、錯誤的堆棧信息,然後將獲取到的所有的信息發送到伺服器中行隱激,也可以發送到指定的郵件中,以檔襪便及時修改bug。
示例:
自定義異常類實現UncaughtExceptionHandler介面,當某個頁面出現異常就會調用uncaughtException這個方法攜山,我們可以在這個方法中獲取異常信息、時間等,然後將獲取到的信息發送到我們指定的伺服器
復制代碼 代碼如下:
/**
* 自定義的 異常處理類 , 實現了 UncaughtExceptionHandler介面
* @author Administrator
*
*/
public class MyCrashHandler implements UncaughtExceptionHandler {
// 需求是 整個應用程序 只有一個 MyCrash-Handler
private static MyCrashHandler myCrashHandler ;
private Context context;
private DoubanService service;
private SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
//1.私有化構造方法
private MyCrashHandler(){
}
public static synchronized MyCrashHandler getInstance(){
if(myCrashHandler!=null){
return myCrashHandler;
}else {
myCrashHandler = new MyCrashHandler();
return myCrashHandler;
}
}
public void init(Context context,DoubanService service){
this.context = context;
this.service = service;
}
public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("程序掛掉了 ");
// 1.獲取當前程序的版本號. 版本的.id
String versioninfo = getVersionInfo();
// 2.獲取手機的硬體信息.
String mobileInfo = getMobileInfo();
// 3.把錯誤的堆棧信息 獲取出來
String errorinfo = getErrorInfo(arg1);
// 4.把所有的信息 還有信息對應的時間 提交到伺服器
try {
service.createNote(new PlainTextConstruct(dataFormat.format(new Date())),
new PlainTextConstruct(versioninfo+mobileInfo+errorinfo), "public", "yes");
} catch (Exception e) {
e.printStackTrace();
}
//幹掉當前的程序
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 獲取錯誤的信息
* @param arg1
* @return
*/
private String getErrorInfo(Throwable arg1) {
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
arg1.printStackTrace(pw);
pw.close();
String error= writer.toString();
return error;
}
/**
* 獲取手機的硬體信息
* @return
*/
private String getMobileInfo() {
StringBuffer sb = new StringBuffer();
//通過反射獲取系統的硬體信息
try {
Field[] fields = Build.class.getDeclaredFields();
for(Field field: fields){
//暴力反射 ,獲取私有的信息
field.setAccessible(true);
String name = field.getName();
String value = field.get(null).toString();
sb.append(name+"="+value);
sb.append("n");
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
/**
* 獲取手機的版本信息
* @return
*/
private String getVersionInfo(){
try {
PackageManager pm = context.getPackageManager();
PackageInfo info =pm.getPackageInfo(context.getPackageName(), 0);
return info.versionName;
} catch (Exception e) {
e.printStackTrace();
return "版本號未知";
}
}
}
創建一個Application實例將MyCrashHandler注冊到整個應用程序上,創建出服務並進行傳遞:
復制代碼 代碼如下:
/**
* 整個(app)程序初始化之前被調用
* @author Administrator
*
*/
public class DoubanApplication extends Application {
public NoteEntry entry;
@Override
public void onCreate() {
super.onCreate();
String apiKey = "";
String secret = "87fc1c5e99bfa5b3";
// 獲取到service
DoubanService myService = new DoubanService("我的小豆豆", apiKey,
secret);
myService.setAccessToken("", "56a622c1138dbfce");
MyCrashHandler handler = MyCrashHandler.getInstance();
handler.init(getApplicationContext(),myService);
Thread.(handler);
}
}
Ⅳ androidstudio中怎麼捕獲異常
//可以使用try catch finally語句來捕獲異常。
//代碼格式:
try{
//如果要捕獲異常,需要將代碼放置在這try的代碼塊范圍內
}catch(IOException ex){//異常范圍IOException 以及它的派生類異常
//此處編寫發生 IOException 或其派生類異常時處理方案
}catch(Exception ex){//異常范圍Exception 以及它的派生類異常
//此處編寫發生Exception 或其派生類異常時處理方案
}finally{
//此處無論上方的代碼中是否出現了異常、return語句,這里必定執行。
}
/*
try catch語句至少需要有一個catch,卻可以同時有多個catch。
其中catch語句塊的異常范圍從上到下順序書寫時應當從小范圍到達范圍,如果將Exception的catch與IOException的catch位置對換,那麼永遠不會執行IOException的catch塊的代碼
finally語句代碼塊是可選的。可以有它,也可以不使用它,具體是否啟用它需要根據業務邏輯決定
*/
Ⅵ android 怎麼捕獲app異常閃退的日誌
1、通過集成第三方SDK,如網路統計、友盟統計等
2、發版時使用加固工具,他們也會收集錯誤日誌,如360加固
3、在程序中添加程序異常崩潰的捕捉代碼,保存到本地文件中。
Ⅶ Android端的用戶行為統計和日誌打撈方案
提到移動客戶端的優化,大家首先想到的可能就是頁面的流暢度,也就是CPU和GPU的渲染問題,以此來提升用戶的體驗,然而對於CPU和GPU渲染的優化又是APP優化的兩把尖刀,讓一個app提升用戶量和體驗度有較高的推動力。然而讓我們無法預估的就是用戶的實際操作,也就是已經發出去的版本,我們很難知道用戶喜歡什麼功能和他們想要什麼功能以及他們習慣於什麼樣的操作姿勢,包括用戶安裝、卸載不用的情況,並且對潛在的線上崩潰問題,作為一位開發者我們就很想知道錯誤出現的精確位置以及錯誤信息,這些對一個APP的成長來說將是一個關鍵的導向作用,其實這也算是APP的一個比較重要的優化方案。
對於以上出現的問題,開發者更關心APP的Crash問題,而對於產品來說,他們更關心用戶的喜好、行為和需求,以便於產品設計出更好的需求解決方案,目前市場上也出現了專門的問題解決方案,比如友盟統計、bugly統計、小米統計等,對於一個小型方案我們可以採用第三方的統計方案,但對於一個日活百萬乃至千萬的APP來說用第三方的統計方案就會受限很多,於是擁有自己的一套統計方案就顯的刻不容緩了,掌握市場的方向,我們就掌握了主動權,那麼我們怎樣去設計一套准確優良的統計方案。
1.1 傳統的pc端統計
以老牌的pc上的web頁面統計一般有PV.UV,和IP之分,對於crash問題,本身web頁面就存在遠程的伺服器端,日誌將會保存在伺服器的目錄,所以一般web項目開發者無需考慮收集Log的case,那麼我們更鋒廳殲care的就是上面說的行為統計,下面說說這三種統計區別。
2. 2、IP、PV和UV分別是什麼意思?
IP,實際上也就是指獨立IP,是獨立IP數的意思。00:00—24:00時間內相同IP地址只記錄一次。即使你有多台電PC,但是如果IP地址是一樣的,那麼也只能算是一個IP的訪問,IP數據依然為1。當然多台pc的ip一般都不一樣,除非你插上同一個網路埠然伏睜後換零一台連接,都是一樣,同時連接多台,每台pc的IP就是不一樣的。
PV, 指訪問量,它的英文是PageView,具體是指網站的是頁面總瀏覽量或者點擊量,頁面被刷新一次就計算一次。如果網站被刷新了10次,那麼流量統計工具顯示的PV就是10 。
UV,它是獨立訪客的意思,英文為Unique Visitor。具體指訪問您網站的一個客戶端(移動設備或者是電PC)為一個訪客。00:00-24:00內相同的客戶端(mac地址區分)只被計算一次。
3 . 3 IP、PV和UV之間的關系是什麼?
1.3.1.IP和PV之間的關系
PV是和IP的數量是成正比的,因為頁面被刷新一次那麼PV就會被記錄一次,所以IP越多,說明網站的PV數據也就隨之增多。但是需要注意的是PV並不是網站的頁面的訪問者數量,而是網站被訪問的頁面數量。因為一個訪問者可以多次刷新頁面,增加PV數量。
1.3.2 .IP和UV之間的關系:
在記錄網站流量統計數據時,運維有時候發現這樣一種情況:有時候網站的IP數據大於UV數據,有時候UV的數據也會大於IP數據。為什麼會出現這種現象呢?我們可以用一個例子來說明。比如,用同一個IP去訪問我們的某個網站,但是一個是用的台式的電腦,一個是用的筆記本,那麼網站流量統計工具顯示的數據就會是2個UV,1個IP。這時UV的數據就會大於IP的數據。但是,再比如,只是用一個台式電腦訪問我們的網站,但是一會撥一個號換一個IP,那麼這時候網站流量統計工具顯示的數據的UV就為1,但是IP的數據就會高於UV的數據。因此,IP和UV之間的數據並不一定存在比例關系,兩者之間銀沖的數據也不是此消彼長的關系。
1.3.3.IP和PV之間的關系:
那麼IP和PV的關系如何呢?如果一個IP刷新了網站100次,網站的PV就為100,所以從這點看二者之間沒有多大關系。但是,我們可以通過IP和PV之間的數據差異,來更加深入的理解網站的流量數據。如果IP和PV的數據懸殊很大,比如,我們在查看網站流量數據時發現網站的PV是1000,IP為100,那麼說明這個站點平均一個IP訪問了網站內容10次,說明網站內容還是比較受歡迎的,所以訪客才願意在網站中停留那麼久的時間,並瀏覽了那麼多的網站頁面內容。但是如果IP和PV的數據很接近,比如,網站的IP為100,PV為110,說明一個IP也就訪問了網站內容大約1次,就說明網站內容的可讀性太差,客戶點擊進去之後就離開了,沒有有過多的停留。如果網站流量統計這樣的數據過多的話,站長就需要對網站內容進行深入思考了,以便更好的提高網站的流量。
1.4 我們能從這邊得到什麼
鑒於已經很成熟的統計方案,我們在移動設備上(這里只說android)怎樣實現一個完美的用戶數據和行為統計,崩潰日誌的套裝方案呢。
那麼我們的一個App,我們能做的那些方面呢
2.1 .1 用戶數據(日活)
首先我們的可以加入ip,PV和UV統計模式,這樣我們可以成功的get到app的日活,以及整體使用情況,
比如App啟動了多少次,訪問了多少h5頁面,有多少個ip(設備)訪問過,但是我們無法得native頁面的信息(也就是Activity)服務端是是無法獲取的,除非我們本地的頁面有載入服務端數據的介面的功能,這種情況下服務是可以監控到本頁面的數據流量的,但是在斷網情況下,服務端是無法及時獲取日活數據的,那麼怎麼解決呢,這里先不說,先看下個要解決的問題。
2.1.2 用戶行為
獲取到了APP整體流量後,怎麼能知道某個功能受歡迎,或者某個本地頁面經常被用戶使用呢,則具體行為統計是app必須的, 目前一般由客戶端和伺服器端協商好一套自定義事件字典(也就是所謂的統計id對照表),當用戶使用某個功能時,我們將對應的功能id發送到後台。這樣服務端就有統計用戶行為的能力了,那麼這種只是一種初次嘗試的想法,那麼斷網,或者功能多的情況子下,我們有如何採集用戶行為呢
2.1.3 Log日誌
那麼對於線上的app版本,又是怎樣收集carsh日誌呢。一般我們在app崩潰的時候發送一條請求到服務端,是可以實現的,但沒必要做,一般是將日誌保存到本地,在某個時間或者case觸發上報行為,
三 綜合方式。
一般統計策略不會採用單一的方式進行上報,多採用組合的形式實現,伺服器和客戶端,有網和沒網,實時和不定時。主動和被動的策略。
1 服務端
客戶端請求介面是 統一包含特定的請求頭,服務端的每個介面中可以去採集這些請求頭 記錄訪問量 包括ip,PV,UV , 這樣可以去捕獲一定的用戶數據。
服戶端也可以採用推送的形式,讓客戶端去發送特定的採集好信息上報給伺服器。
2 客戶端
統計一般大多體現在客戶端,我們可以將一個整體的app分解成多個模塊,每個模塊有多個功能,功能又分為用戶主動和被動接受之分,給每個域分配一定的ID,那麼在用戶使用某個功能時 我們動態記錄這個ID(比如登陸和注冊一般屬於用戶中心(001),登陸和注冊輸入兩種功能,分別給03,04標記,登陸屬於用戶主動 那麼可以給 01,注冊被動跳轉給02), 最後寫入到本地保存,那麼用戶打開用戶中心登陸產生的的數據信息就0010201 ,這樣伺服器能知道,我們只要在某個時間點將文本數據上傳即可,即使沒網路情況下我們也不怕,等設備有網的情況下 我們偷偷上報即可,那麼我們也可以在用戶登陸的時候時侯同時就上傳這些數據,這個策略視具體功而定。
一般一個APP統計有模塊域 ,功能域,事件域,由大到小分配而來,也有按頁面區分的,具體看實際的需求場景而定
對於我們的app crash 我們可以繼承android自帶的全局異常類(UncaughtExceptionHandler),來進行自我捕獲異常,和用戶行為一起上報。
也可以單獨加個意見反饋功能,採集用戶的吐槽和建議。
說了上面一大堆策略問題,對於開發而言很可能覺得很無聊,那麼至於統計其實沒什麼技術含量(用戶設備的唯一標識符除外),無非就是採集數據寫到文件中,請求發送數據,最重要的還是一種策略的定義。
主流的多採用 時間戳,內存大小(日誌積累到多大位元組),次數(總計積累到多十條)等,
對於好的統計,我們可以檢測網路,檢測home建來觸發我們的上報數據介面,也可以採用注冊靜態廣播,用alarm 鬧鍾定時上報數據,然後這些技術也就是被大家玩透的功能而已,沒必要再這里給大家補腦,但是注意的是
統計設備唯一標識符的確定, 這個以後再去分析.
統計上報介面採用分布式,不然所有數據都請求同一個介面,那麼日活大的情況下,伺服器掛了 不僅無法收到數據,反而影響客戶端其他正常的功能
Ⅷ android 如何讓應用程序只在有中斷的時候才運行
在application中捕獲全局異常,當有異常發生時,做你要做的事情。
Ⅸ android 程序怎樣捕捉全局異常
Android系統的「程序異常退出」,給應用的用戶體驗造成不良影響。為了捕獲應用運行時異常並給出友好提示,便可繼承UncaughtExceptionHandler類來處理。通過Thread.()方法將異常處理類設置到線程族寬上即可。
1、異常處理類,喊山代碼如兆滲亮下:
[java] view plain
public class CrashHandler implements UncaughtExceptionHandler {
public static final String TAG = "CrashHandler";
private static CrashHandler INSTANCE = new CrashHandler();
private Context mContext;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private CrashHandler() {
}
public static CrashHandler getInstance() {
return INSTANCE;
}
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.();
Thread.(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
// if (!handleException(ex) && mDefaultHandler != null) {
// mDefaultHandler.uncaughtException(thread, ex);
// } else {
// android.os.Process.killProcess(android.os.Process.myPid());
// System.exit(10);
// }
System.out.println("uncaughtException");
new Thread() {
@Override
public void run() {
Looper.prepare();
new AlertDialog.Builder(mContext).setTitle("提示").setCancelable(false)
.setMessage("程序崩潰了...").setNeutralButton("我知道了", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
})
.create().show();
Looper.loop();
}
}.start();
}
/**
* 自定義錯誤處理,收集錯誤信息 發送錯誤報告等操作均在此完成. 開發者可以根據自己的情況來自定義異常處理邏輯
*
* @param ex
* @return true:如果處理了該異常信息;否則返回false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return true;
}
// new Handler(Looper.getMainLooper()).post(new Runnable() {
// @Override
// public void run() {
// new AlertDialog.Builder(mContext).setTitle("提示")
// .setMessage("程序崩潰了...").setNeutralButton("我知道了", null)
// .create().show();
// }
// });
return true;
}
}
2、線程綁定異常處理類
[java] view plain
public class CrashHandlerActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(this); //傳入參數必須為Activity,否則AlertDialog將不顯示。
// 創建錯誤
throw new NullPointerException();
}
}