日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android热修复之 - 收集崩溃信息上传服务器

發布時間:2025/3/15 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android热修复之 - 收集崩溃信息上传服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1.概述

大致的流程就是在用戶崩潰的時候,我們獲取崩潰信息、應用當前的信息和手機信息,然后把它保存到手機內存卡,再找我就直接找出來看看。后來衍生到上線后某些奇葩機型會有部分問題,所以不得不上傳到服務器,后來發現居然可以配合熱修復一步一步如此神奇,接下來我們來玩一玩,如何才能把用戶的崩潰信息上傳到服務器。大家也可以去找騰訊他有現成的:https://bugly.qq.com/v2/index 友盟也有現成的:http://www.umeng.com/ 實現的原理都類似。

2.實現


2.1 攔截閃退信息
  
  如何去收集我們的閃退信息?我們需要認識一下這個類Thread.UncaughtExceptionHandler,一言不和就看源碼,這個可以不看,且看我是如何寫的。

攔截應用的閃退信息

1 public class ExceptionCrashHandler implements Thread.UncaughtExceptionHandler { 2 3 private static final String TAG = "ExceptionCrashHandler"; 4 // 單例設計模式 5 private static ExceptionCrashHandler mInstance; 6 // 留下原來的,便于開發的時候調試 7 private Thread.UncaughtExceptionHandler mDefaultHandler; 8 // 上下文 獲取版本信息和手機信息 9 private Context mContext; 10 11 public static ExceptionCrashHandler getInstance() { 12 if (mInstance == null) { 13 synchronized (ExceptionCrashHandler.class) { 14 if (mInstance == null) { 15 mInstance = new ExceptionCrashHandler(); 16 } 17 } 18 } 19 return mInstance; 20 } 21 22 private ExceptionCrashHandler() { 23 24 } 25 26 public void init(Context context) { 27 /** 28 * 官方解釋 29 * Set the handler invoked when this thread abruptly terminates 30 * due to an uncaught exception. 31 **/ 32 Thread.currentThread().setUncaughtExceptionHandler(this); 33 // 獲取系統默認的UncaughtException處理器 34 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 35 this.mContext = context; 36 } 37 38 @Override 39 public void uncaughtException(Thread t, Throwable ex) { 40 Log.e(TAG, "到攔截閃退信息"); 41 } 42 43 }

在Application的onCreate()中配置一下,然后在任何一個地方寫一個異常試一試:

public class BaseApplication extends Application {@Overridepublic void onCreate() {super.onCreate();ExceptionCrashHandler.getInstance().init(this);} }

2.2 收集閃退信息

  這樣每次崩潰的時候都會進入uncaughtException(),這個時候我們只需要收集信息寫入本地文件就好了,收集的信息肯定需要包含好幾個部分:當前崩潰信息,當前應用的版本信息,當前手機的信息,有的時候我們還需要其他部分,這里大概就只收集這三部分。為什么收集收集手機信息呢?因為有的時候是由于某些特定手機引起的Bug,若怪罪下來的話我們要甩鍋給他。

1 @Override 2 public void uncaughtException(Thread t, Throwable ex) { 3 Log.e(TAG, "捕捉到了異常"); 4 // 1. 獲取信息 5 // 1.1 崩潰信息 6 // 1.2 手機信息 7 // 1.3 版本信息 8 // 2.寫入文件 9 String crashFileName = saveInfoToSD(ex); 10 11 Log.e(TAG, "fileName --> " + crashFileName); 12 13 // 3. 緩存崩潰日志文件 14 cacheCrashFile(crashFileName); 15 // 系統默認處理 16 mDefaultHandler.uncaughtException(t, ex); 17 } 18 19 /** 20 * 緩存崩潰日志文件 21 * 22 * @param fileName 23 */ 24 private void cacheCrashFile(String fileName) { 25 SharedPreferences sp = mContext.getSharedPreferences("crash", Context.MODE_PRIVATE); 26 sp.edit().putString("CRASH_FILE_NAME", fileName).commit(); 27 } 28 29 30 /** 31 * 獲取崩潰文件名稱 32 * 33 * @return 34 */ 35 public File getCrashFile() { 36 String crashFileName = mContext.getSharedPreferences("crash", 37 Context.MODE_PRIVATE).getString("CRASH_FILE_NAME", ""); 38 return new File(crashFileName); 39 } 40 41 /** 42 * 保存獲取的 軟件信息,設備信息和出錯信息保存在SDcard中 43 * 44 * @param ex 45 * @return 46 */ 47 private String saveInfoToSD(Throwable ex) { 48 String fileName = null; 49 StringBuffer sb = new StringBuffer(); 50 51 for (Map.Entry<String, String> entry : obtainSimpleInfo(mContext) 52 .entrySet()) { 53 String key = entry.getKey(); 54 String value = entry.getValue(); 55 sb.append(key).append(" = ").append(value).append("\n"); 56 } 57 58 sb.append(obtainExceptionInfo(ex)); 59 60 if (Environment.getExternalStorageState().equals( 61 Environment.MEDIA_MOUNTED)) { 62 File dir = new File(mContext.getFilesDir() + File.separator + "crash" 63 + File.separator); 64 65 // 先刪除之前的異常信息 66 if (dir.exists()) { 67 deleteDir(dir); 68 } 69 70 // 再從新創建文件夾 71 if (!dir.exists()) { 72 dir.mkdir(); 73 } 74 try { 75 fileName = dir.toString() 76 + File.separator 77 + getAssignTime("yyyy_MM_dd_HH_mm") + ".txt"; 78 FileOutputStream fos = new FileOutputStream(fileName); 79 fos.write(sb.toString().getBytes()); 80 fos.flush(); 81 fos.close(); 82 } catch (Exception e) { 83 e.printStackTrace(); 84 } 85 } 86 return fileName; 87 } 88 89 /** 90 * 返回當前日期根據格式 91 **/ 92 private String getAssignTime(String dateFormatStr) { 93 DateFormat dataFormat = new SimpleDateFormat(dateFormatStr); 94 long currentTime = System.currentTimeMillis(); 95 return dataFormat.format(currentTime); 96 } 97 98 99 /** 100 * 獲取一些簡單的信息,軟件版本,手機版本,型號等信息存放在HashMap中 101 * 102 * @return 103 */ 104 private HashMap<String, String> obtainSimpleInfo(Context context) { 105 HashMap<String, String> map = new HashMap<>(); 106 PackageManager mPackageManager = context.getPackageManager(); 107 PackageInfo mPackageInfo = null; 108 try { 109 mPackageInfo = mPackageManager.getPackageInfo( 110 context.getPackageName(), PackageManager.GET_ACTIVITIES); 111 } catch (PackageManager.NameNotFoundException e) { 112 e.printStackTrace(); 113 } 114 map.put("versionName", mPackageInfo.versionName); 115 map.put("versionCode", "" + mPackageInfo.versionCode); 116 map.put("MODEL", "" + Build.MODEL); 117 map.put("SDK_INT", "" + Build.VERSION.SDK_INT); 118 map.put("PRODUCT", "" + Build.PRODUCT); 119 map.put("MOBLE_INFO", getMobileInfo()); 120 return map; 121 } 122 123 124 /** 125 * Cell phone information 126 * 127 * @return 128 */ 129 public static String getMobileInfo() { 130 StringBuffer sb = new StringBuffer(); 131 try { 132 Field[] fields = Build.class.getDeclaredFields(); 133 for (Field field : fields) { 134 field.setAccessible(true); 135 String name = field.getName(); 136 String value = field.get(null).toString(); 137 sb.append(name + "=" + value); 138 sb.append("\n"); 139 } 140 } catch (Exception e) { 141 e.printStackTrace(); 142 } 143 return sb.toString(); 144 } 145 146 147 /** 148 * 獲取系統未捕捉的錯誤信息 149 * 150 * @param throwable 151 * @return 152 */ 153 private String obtainExceptionInfo(Throwable throwable) { 154 StringWriter stringWriter = new StringWriter(); 155 PrintWriter printWriter = new PrintWriter(stringWriter); 156 throwable.printStackTrace(printWriter); 157 printWriter.close(); 158 return stringWriter.toString(); 159 } 160 161 162 /** 163 * 遞歸刪除目錄下的所有文件及子目錄下所有文件 164 * 165 * @param dir 將要刪除的文件目錄 166 * @return boolean Returns "true" if all deletions were successful. If a 167 * deletion fails, the method stops attempting to delete and returns 168 * "false". 169 */ 170 private boolean deleteDir(File dir) { 171 if (dir.isDirectory()) { 172 String[] children = dir.list(); 173 // 遞歸刪除目錄中的子目錄下 174 for (int i = 0; i < children.length; i++) { 175 boolean success = deleteDir(new File(dir, children[i])); 176 if (!success) { 177 return false; 178 } 179 } 180 } 181 // 目錄此時為空,可以刪除 182 return true; 183 }

保存的路徑最好不要在用戶的外部存儲卡中,因為6.0的時候如果訪問外部存儲卡需要動態的申請權限,那這個時候信息是獲取到了但是GG。都蹦了還拖著我不放,還需要申請權限,納尼???

2.2 上傳閃退信息

每次啟動應用的時候就獲取上次閃退的信息日志,然后上傳到服務器。

public class MainActivity extends BaseActivity {@Overrideprotected void initData() {// 獲取上次的崩潰信息File crashFile = ExceptionCrashHandler.getInstance().getCrashFile();// 上傳到服務器,后面再說....... }@Overrideprotected void initView() {}@Overrideprotected void setContentView() {setContentView(R.layout.activity_main);}@Overrideprotected void initTitle() {} }

?

http://www.cnblogs.com/ganchuanpu/p/8196771.html

總結

以上是生活随笔為你收集整理的Android热修复之 - 收集崩溃信息上传服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。