android實用方法----程式碼中抓取log
阿新 • • 發佈:2019-01-22
最近在公司中遇到一個需求,客戶的手機出現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