第13章 综合技术

使用CrashHandler来获取crash信息;

当程序crash时,会调用CrashHandler的uncaughtException方法,在这个方法中获取crash信息并上传服务器来监控。import java.io.BufferedWriter;import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;
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.Environment;
import android.os.Process;
import android.util.Log;

publicclassCrashHandlerimplementsUncaughtExceptionHandler{
    privatestaticfinalString TAG ="CrashHandler";
    privatestaticfinalboolean DEBUG =true;
    privatestaticfinalString PATH =Environment.getExternalStorageDirectory().getPath()+"/CrashTest/log/";
    privatestaticfinalString FILE_NAME ="crash";
    privatestaticfinalString FILE_NAME_SUFFIX =".trace";
    privatestaticCrashHandler sInstance =newCrashHandler();
    privateUncaughtExceptionHandler mDefaultCrashHandler;
    privateContext mContext;
privateCrashHandler(){ } publicstaticCrashHandler getInstance(){
return sInstance; } public void init(Context context){ mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this);//设置为线程默认的异常处理器 mContext = context.getApplicationContext(); } /** * 这个是最关键的函数,当程序中有未被捕获的异常,系统将会自动调用 #uncaughtException方法 * thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex, 我们就可以得到异常信息。 */ @Override publicvoid uncaughtException(Thread thread,Throwable ex){ try{ //导出异常信息到SD卡中 dumpExceptionToSDCard(ex); uploadExceptionToServer(); //这里可以通过网络上传异常信息到服务器,便于开发人员分析日志从 而解决bug }catch(IOException e){ e.printStackTrace(); } ex.printStackTrace(); //如果系统提供了默认的异常处理器,则交给系统去结束我们的程序,否则就由我们自己结束自己 if(mDefaultCrashHandler !=null){ mDefaultCrashHandler.uncaughtException(thread, ex); }else{ Process.killProcess(Process.myPid()); } }
privatevoid dumpExceptionToSDCard(Throwable ex)throwsIOException{
//如果SD卡不存在或无法使用,则无法把异常信息写入SD卡 if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ if(DEBUG){ Log.w(TAG,"sdcard unmounted,skip dump exception"); return; } } File dir =newFile(PATH); if(!dir.exists()){ dir.mkdirs(); }
long current =System.currentTimeMillis(); String time =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(newDate(current)); File file =newFile(PATH + FILE_NAME + time + FILE_NAME_SUFFIX);   try{       PrintWriter pw =newPrintWriter(newBufferedWriter(newFileWriter(file)));       pw.println(time);       dumpPhoneInfo(pw);       pw.println();       ex.printStackTrace(pw);       pw.close();     }catch(Exception e){       Log.e(TAG,"dump crash info failed");     }   }   privatevoid dumpPhoneInfo(PrintWriter pw)throwsNameNotFoundException{   PackageManager pm = mContext.getPackageManager();   PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),PackageManager.GET_ACTIVITIES);   pw.print("App Version: ");   pw.print(pi.versionName);   pw.print('_');   pw.println(pi.versionCode);   //android版本号   pw.print("OS Version: ");   pw.print(Build.VERSION.RELEASE);   pw.print("_");   pw.println(Build.VERSION.SDK_INT);   //手机制造商   pw.print("Vendor: ");   pw.println(Build.MANUFACTURER);   //手机型号   pw.print("Model: ");   pw.println(Build.MODEL);   //cpu架构   pw.print("CPU ABI: ");   pw.println(Build.CPU_ABI); }   privatevoid uploadExceptionToServer(){     //TODO Upload Exception Message To Your Web Server   } }
使用的时候,在application代码里。
//在这里为应用设置异常处理程序,然后我们的程序才能捕获未处理的异常
CrashHandler crashHandler =CrashHandler.getInstance();
crashHandler.init(this);
使用multidex来解决方法数越界;
应用的方法数不能超过65536,通过将一个dex文件拆分多个dex文件来避免dex文件方法数越界问题。
android5.0以前引入google提供的android-support-multidex.jar,这个jar在SDK的extras/android/multidex/library/libs。
5.0以后默认支持,在AS里面使用。
 
配置app的build.gradle文件
defaultConfig添加
//enable muitidex support
multiDexEnabled true
dependencies添加依赖
compile 'com.android.support:multidex:1.0.0'
最后一步,代码中加入支持multidex功能
三种方法
1、manifest文件指定Application为MultiDexApplication
<application
android:name="android.support.multidex.MultiDexApplication"
2、Application继承MultiDexApplication
3、Application不继承MultiDexApplication,重写Application的attachBaseContext方法。
@override
protectedvoid attachBaseContext(Context base){
    super.attachBaseContext(base);
    MultiDex.install(this);
}
指定放在主dex,在build.gradle中添加afterEvaluate,并要写maindexlist.txt文件。multidex的jar包的几个类必须打包到主dex。
android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDex$V4.class
android/support/multidex/MultiDex$V14.class
android/support/multidex/MultiDex$V19.class
android/support/multidex/ZipUtil.class
android/support/multidex/ZipUtil$CentralDirectory.class
afterEvaluate{
    println "afterEvaluate"
    tasks.matching{
    it.name.startsWith('dex')
    }.each{de->
        def listFile = project.rootDir.absolutePath +'/app/maindexlist.txt'
        println "root dir:"+ project.rootDir.absolutePath
        println "dex task found:"+de.name
        if(dx.additionalParameters ==null){
           de.additionParameters=[]
        }
     de.additionParameters +='--multi-dex'//当方法数越界时则生成多个dex文件
     de.additionParameters +='--main-dex-list='+listFile //指定了要在主dex中打包的类列表
     de.additionParameters +='--minimal-main-dex'//只有main-dex-list所指定的类才能打包到主dex中
  }
}    
动态加载
开源插件化框架DL:
解决基础性问题:资源访问、Activity生命周期管理、ClassLoader管理。
 
反编译
dex2jjar将apk转称一个jar,jar再通过jd-gui打开能看到java代码,Apktool用于应用的解包和二次打包。

 

posted @ 2016-03-02 16:32  咖啡馆的水果拼盘  阅读(163)  评论(0编辑  收藏  举报