最近在公司中遇到一个需求,客户的手机出现bug但是我们复现不出来,所以我们主管让我写个抓log的apk。
思路很简单,开启一个服务,然后用Runtime.getRuntime().exec(String [] cmdArray);方法调用命令行执行adb命令就好。
给大家贴上代码LogObserverService
package com.kukool.game.Service;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import com.kukool.game.ddz.MainActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 抓log的服务
*/
public class LogObserverService extends Service implements Runnable {
private String TAG = "LogObserverService";
private boolean isObserverLog = false;
private StringBuffer logContent = null;
private Bundle mBundle = null;
private Intent mIntent = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("TrafficService","startCommand");
//START_STICKY是service被kill掉后自动重写创建
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG,"onCreate");
mIntent = new Intent();
mBundle = new Bundle();
logContent = new StringBuffer();
startLogObserver();
}
/**
* 开启检测日志
*/
public void startLogObserver() {
Log.i(TAG,"startObserverLog");
isObserverLog = true;
Thread mTherad = new Thread(this);
mTherad.start();
}
/**
* 关闭检测日志
*/
public void stopLogObserver() {
isObserverLog = false;
}
@Override
public void onDestroy() {
super.onDestroy();
stopLogObserver();
}
/**
* 发送log内容
* @param logContent
*/
private void sendLogContent(String logContent){
mBundle.putString("log",logContent);
mIntent.putExtras(mBundle);
mIntent.setAction(MainActivity.LOG_ACTION);
sendBroadcast(mIntent);
}
@Override
public void run() {
Process pro = null;
BufferedReader bufferedReader = null;
try {
String[] running=new String[]{ "logcat","|find","cocos2d-x debug" };
// pro = Runtime.getRuntime().exec("logcat");
pro = Runtime.getRuntime().exec(running);
// Runtime.getRuntime().exec("logcat -c").waitFor();
bufferedReader = new BufferedReader(new InputStreamReader(
pro.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
//筛选需要的字串
String strFilter="cocos2d-x debug";
String line = null;
try {
Log.e("走到这里没","走到这里没");
System.out.println(bufferedReader.readLine());
while ((line =bufferedReader.readLine()) != null) {
Log.e("走到这里没","走到这里没");
if (line.indexOf(strFilter) >=0) {
//读出每行log信息
System.out.println(line);
logContent.delete(0,logContent.length());
logContent.append(line);
logContent.append("\n");
//发送log内容
sendLogContent(logContent.toString());
Thread.yield();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
别忘了在清单文件中加上
<service android:name=".LogObserverService" />
还有权限
<uses-permission android:name="android.permission.READ_LOGS" />
然后是测试代码,具体你们可以改动
package com.example.admin.logobserver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.io.File;
import java.io.FileOutputStream;
public class MainActivity extends AppCompatActivity {
private String TAG = "LogObserverActivity";
public static String LOG_ACTION = "com.example.admin.logobserver.LOG_ACTION";
private TextView logContent = null;
private Button start = null;
private Intent logObserverIntent = null;
private LogBroadcastReceiver mLogBroadcastReceiver = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化视图
initView();
//注册log广播接收者
registerLogBroadcastReceiver();
}
private void initView() {
logContent = (TextView) findViewById(R.id.logContent);
logContent.setText("show log");
start = (Button)findViewById(R.id.start);
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startLogObserverService();
start.setEnabled(false);
}
});
}
private void startLogObserverService() {
logObserverIntent = new Intent(this, LogObserverService.class);
startService(logObserverIntent);
}
/**
* 注册log广播接收者
*/
private void registerLogBroadcastReceiver(){
mLogBroadcastReceiver = new LogBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(LOG_ACTION);
registerReceiver(mLogBroadcastReceiver, filter);
}
/**
* log 广播接收者
* @author zhangyg
*
*/
private class LogBroadcastReceiver extends BroadcastReceiver {
private String action = null;
private Bundle mBundle = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if(LOG_ACTION.equals(action)){
mBundle = intent.getExtras();
Log.e("log接收","log&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
logContent.setText(mBundle.getString("log"));
writeToSdCard(mBundle.getString("log"));
}
}
}
//写数据
public void writeToSdCard(String string){
//1、判断sd卡是否可用
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
//sd卡可用
//2、获取sd卡路径
File sdFile=Environment.getExternalStorageDirectory();
File path=new File(sdFile,"360/a.txt");//sd卡下面的a.txt文件 参数 前面 是目录 后面是文件
try {
FileOutputStream fileOutputStream=new FileOutputStream(path,true);
fileOutputStream.write(string.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (logObserverIntent!=null){
stopService(logObserverIntent);
}
if (mLogBroadcastReceiver!=null){
unregisterReceiver(mLogBroadcastReceiver);
}
}
}
这就可以了,但是这个只能嵌套在你项目中不能做成APK因为只能获取自己项目的log,原因是 android.permission.READ_LOGS:app读取日志权限,android 4.1之前版本通过申请READ_LOGS权限就可以读取其他应用的log了。但是谷歌发现这样存在安全风险,于是android 4.1以及之后版本,即使申请了READ_LOGS权限也无法读取其他应用的日志信息了。4.1版本中 Logcat的签名变为 “signature|system|development”了,这意味着只有系统签名的app或者root权限的app才能使用该权限。普通用户可以通过ADB查看所有日志。
简单说就是谷歌觉得危险干掉了,你又不可能叫客户刷机,所以就是嵌套在你的项目中。
对了过滤我用的 adb logcat |find “保留的log”
还可以用 adb logcat -s 你想看的类的log