gpt4 book ai didi

android - 需要处理未捕获的异常并发送日志文件

转载 作者:IT老高 更新时间:2023-10-28 13:03:42 28 4
gpt4 key购买 nike

当我的应用程序创建一个未处理的异常,而不是简单地终止时,我想首先让用户有机会发送一个日志文件。我意识到在遇到随机异常后做更多的工作是有风险的,但是,嘿,最糟糕的是应用程序完成崩溃并且没有发送日志文件。事实证明这比我预期的要棘手:)

工作原理:(1) 捕获未捕获的异常,(2) 提取日志信息并写入文件。

什么还不起作用:(3)开始一个 Activity 来发送电子邮件。最终,我将进行另一项 Activity 来征求用户的许可。如果我让电子邮件 Activity 正常工作,我预计对方不会有太多麻烦。

问题的症结在于我的 Application 类中捕获了未处理的异常。由于那不是 Activity,因此如何使用 Intent.ACTION_SEND 启动 Activity 并不明显。也就是说,通常要启动一项 Activity ,需要调用 startActivity 并使用 onActivityResult 恢复。 Activity 支持这些方法,但 Application 不支持。

关于如何做到这一点的任何建议?

以下是一些代码 fragment 作为入门指南:

public class MyApplication extends Application
{
defaultUncaughtHandler = Thread.getDefaultUncaughtExceptionHandler();
public void onCreate ()
{
Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler()
{
@Override
public void uncaughtException (Thread thread, Throwable e)
{
handleUncaughtException (thread, e);
}
});
}

private void handleUncaughtException (Thread thread, Throwable e)
{
String fullFileName = extractLogToFile(); // code not shown

// The following shows what I'd like, though it won't work like this.
Intent intent = new Intent (Intent.ACTION_SEND);
intent.setType ("plain/text");
intent.putExtra (Intent.EXTRA_EMAIL, new String[] {"me@mydomain.example"});
intent.putExtra (Intent.EXTRA_SUBJECT, "log file");
intent.putExtra (Intent.EXTRA_STREAM, Uri.parse ("file://" + fullFileName));
startActivityForResult (intent, ACTIVITY_REQUEST_SEND_LOG);
}

public void onActivityResult (int requestCode, int resultCode, Intent data)
{
if (requestCode == ACTIVITY_REQUEST_SEND_LOG)
System.exit(1);
}
}

最佳答案

这是完整的解决方案(几乎是:我省略了 UI 布局和按钮处理) - 源自大量实验以及其他与此过程中出现的问题相关的各种帖子。

你需要做很多事情:

  1. 在您的 Application 子类中处理 uncaughtException。
  2. 捕获异常后,启动一个新的 Activity 来要求用户发送日志。
  3. 从 logcat 的文件中提取日志信息并写入您的自己的文件。
  4. 启动一个电子邮件应用,将您的文件作为附件提供。
  5. list :过滤您的 Activity 以被您的异常处理程序识别。
  6. (可选)设置 Proguard 以去除 Log.d()Log.v()

现在,这里是详细信息:

(1 & 2) 处理 uncaughtException,开始发送日志 Activity :

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 Activity 中):

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 Activity 中):

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.example"});
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) list :

<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 中,更改配置行。您必须指定“优化”,否则 Proguard 不会删除 Log.v()Log.d() 调用。

proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt

proguard-project.txt 中,添加以下内容。这告诉 Proguard 假设 Log.vLog.d 没有副作用(即使它们在写入日志时有副作用),因此可以在优化期间删除:

-assumenosideeffects class android.util.Log {
public static int v(...);
public static int d(...);
}

就是这样!如果您对此有任何改进建议,请告诉我,我可能会对此进行更新。

关于android - 需要处理未捕获的异常并发送日志文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19897628/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com