您的位置:首页 > 其它

第13章 综合技术

2016-03-02 16:32 736 查看
使用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:
GItHub:https://github.com/singwhatiwanna/dynamic-load-apk
/article/1603770.html
解决基础性问题:资源访问、Activity生命周期管理、ClassLoader管理。

反编译
dex2jjar将apk转称一个jar,jar再通过jd-gui打开能看到java代码,Apktool用于应用的解包和二次打包。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: