1. 程式人生 > >android實用方法----程式碼中抓取log

android實用方法----程式碼中抓取log

最近在公司中遇到一個需求,客戶的手機出現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