여기에 완전한 솔루션이 있습니다 (거의 : UI 레이아웃과 버튼 처리를 생략했습니다)-많은 실험과 그 과정에서 발생한 문제와 관련된 다른 사람들의 다양한 게시물에서 파생되었습니다.
다음과 같은 여러 가지 작업을 수행해야합니다.
- Application 하위 클래스에서 uncaughtException을 처리합니다.
- 예외를 포착 한 후 새 활동을 시작하여 사용자에게 로그를 보내도록 요청하십시오.
- logcat의 파일에서 로그 정보를 추출하고 자신의 파일에 씁니다.
- 이메일 앱을 시작하여 파일을 첨부 파일로 제공합니다.
- 매니페스트 : 예외 처리기가 인식하도록 활동을 필터링합니다.
- 선택적으로 Log.d () 및 Log.v ()를 제거하도록 Proguard를 설정합니다.
이제 세부 정보는 다음과 같습니다.
(1 & 2) uncaughtException 처리, 로그 활동 보내기 시작 :
public class MyApplication extends Application
{
public void onCreate ()
{
// Setup handler for uncaught exceptions.
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
@Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
}
public void handleUncaughtException (Thread thread, Throwable e)
{
e.printStackTrace(); // not all Android versions will print the stack trace automatically
Intent intent = new Intent ();
intent.setAction ("com.mydomain.SEND_LOG"); // see step 5.
intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK); // required when starting from Application
startActivity (intent);
System.exit(1); // kill off the crashed app
}
}
(3) 로그 추출 (내 SendLog 활동에 넣습니다) :
private String extractLogToFile()
{
PackageManager manager = this.getPackageManager();
PackageInfo info = null;
try {
info = manager.getPackageInfo (this.getPackageName(), 0);
} catch (NameNotFoundException e2) {
}
String model = Build.MODEL;
if (!model.startsWith(Build.MANUFACTURER))
model = Build.MANUFACTURER + " " + model;
// Make file name - file must be saved to external storage or it wont be readable by
// the email app.
String path = Environment.getExternalStorageDirectory() + "/" + "MyApp/";
String fullName = path + <some name>;
// Extract to file.
File file = new File (fullName);
InputStreamReader reader = null;
FileWriter writer = null;
try
{
// For Android 4.0 and earlier, you will get all app's log output, so filter it to
// mostly limit it to your app's output. In later versions, the filtering isn't needed.
String cmd = (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) ?
"logcat -d -v time MyApp:v dalvikvm:v System.err:v *:s" :
"logcat -d -v time";
// get input stream
Process process = Runtime.getRuntime().exec(cmd);
reader = new InputStreamReader (process.getInputStream());
// write output stream
writer = new FileWriter (file);
writer.write ("Android version: " + Build.VERSION.SDK_INT + "\n");
writer.write ("Device: " + model + "\n");
writer.write ("App version: " + (info == null ? "(null)" : info.versionCode) + "\n");
char[] buffer = new char[10000];
do
{
int n = reader.read (buffer, 0, buffer.length);
if (n == -1)
break;
writer.write (buffer, 0, n);
} while (true);
reader.close();
writer.close();
}
catch (IOException e)
{
if (writer != null)
try {
writer.close();
} catch (IOException e1) {
}
if (reader != null)
try {
reader.close();
} catch (IOException e1) {
}
// You might want to write a failure message to the log here.
return null;
}
return fullName;
}
(4) 이메일 앱 시작 (내 SendLog 활동에서도) :
private void sendLogFile ()
{
String fullName = extractLogToFile();
if (fullName == null)
return;
Intent intent = new Intent (Intent.ACTION_SEND);
intent.setType ("plain/text");
intent.putExtra (Intent.EXTRA_EMAIL, new String[] {"log@mydomain.com"});
intent.putExtra (Intent.EXTRA_SUBJECT, "MyApp log file");
intent.putExtra (Intent.EXTRA_STREAM, Uri.parse ("file://" + fullName));
intent.putExtra (Intent.EXTRA_TEXT, "Log file attached."); // do this so some email clients don't complain about empty body.
startActivity (intent);
}
(3 & 4) SendLog의 모습은 다음과 같습니다 (하지만 UI를 추가해야합니다).
public class SendLog extends Activity implements OnClickListener
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature (Window.FEATURE_NO_TITLE); // make a dialog without a titlebar
setFinishOnTouchOutside (false); // prevent users from dismissing the dialog by tapping outside
setContentView (R.layout.send_log);
}
@Override
public void onClick (View v)
{
// respond to button clicks in your UI
}
private void sendLogFile ()
{
// method as shown above
}
private String extractLogToFile()
{
// method as shown above
}
}
(5) 매니페스트 :
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
<!-- needed for Android 4.0.x and eariler -->
<uses-permission android:name="android.permission.READ_LOGS" />
<application ... >
<activity
android:name="com.mydomain.SendLog"
android:theme="@android:style/Theme.Dialog"
android:textAppearance="@android:style/TextAppearance.Large"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="com.mydomain.SEND_LOG" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
(6) Proguard 설치 :
project.properties에서 구성 줄을 변경합니다. "optimize"를 지정해야합니다. 그렇지 않으면 Proguard가 Log.v () 및 Log.d () 호출을 제거 하지 않습니다 .
proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
proguard-project.txt에서 다음을 추가합니다. 이렇게하면 Proguard에 Log.v 및 Log.d가 부작용이 없다고 가정하고 (로그에 기록한 이후에도 마찬가지 임) 최적화 중에 제거 할 수 있습니다.
-assumenosideeffects class android.util.Log {
public static int v(...);
public static int d(...);
}
그게 다야! 개선에 대한 제안이있는 경우 알려 주시면 업데이트하겠습니다.