【问题标题】:Updating an APK更新 APK
【发布时间】:2018-11-04 17:09:04
【问题描述】:

我们有一个在启动时检查更新的内部应用。它没有在 Play Store 上发布,因为它仅供内部使用。

下面的更新代码在我的测试设备 (API 23) 上运行良好。但是我最近发布了一个更新,可以在测试设备上下载但报告:

解析错误 - 解析包时出现问题

在我自己的设备 (API 24) 上,该应用会下载该应用,然后崩溃。

public class UpdateApp extends AsyncTask<String,Void,Void> {
    private Context context;
    public void setContext(Context contextf){
        context = contextf;
    }

    @Override
    protected Void doInBackground(String... arg0) {
        try {
            URL url = new URL(arg0[0]);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setDoOutput(true);
            conn.connect();

            File file = context.getCacheDir();
            file.mkdirs();
            outputFile = new File(file, "update.apk");
            if(outputFile.exists()){
                outputFile.delete();
            }
            FileOutputStream fos = new FileOutputStream(outputFile);

            InputStream is = conn.getInputStream();

            byte[] buffer = new byte[1024];
            int len1 = 0;
            while ((len1 = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len1);
            }
            fos.close();
            is.close();
            outputFile.setReadable(true, false);

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);

        } catch (Throwable ex) {
            Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
        }
        return null;
    }

在两台设备上,更新的 APK 都会在引发错误 (API 23) 或崩溃 (API 24) 之前下载。我不明白应用程序是如何崩溃的,因为所有代码都在 try 块中,其中 catch 用于 Throwable 类,所以它应该 catch 所有错误和异常!

以下是我的 API 24 设备在下载文件后更新时的logcat 输出。除了指出AysncTask 类的问题外,我无法从中找出任何有用的东西。

2018-11-04 16:47:27.593 966-1017/? E/PROXIMITY: ProximitySensor: unknown event (type=3, code=0)
2018-11-04 16:47:27.704 23431-23476/uk.co.letsdelight.letsdelight E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
    Process: uk.co.letsdelight.letsdelight, PID: 23431
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$3.done(AsyncTask.java:318)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
        at java.util.concurrent.FutureTask.run(FutureTask.java:242)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:761)
     Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
        at android.os.Handler.<init>(Handler.java:208)
        at android.os.Handler.<init>(Handler.java:122)
        at android.widget.Toast$TN.<init>(Toast.java:351)
        at android.widget.Toast.<init>(Toast.java:106)
        at android.widget.Toast.makeText(Toast.java:265)
        at uk.co.letsdelight.letsdelight.Update$UpdateApp.doInBackground(Update.java:123)
        at uk.co.letsdelight.letsdelight.Update$UpdateApp.doInBackground(Update.java:83)
        at android.os.AsyncTask$2.call(AsyncTask.java:304)
        at java.util.concurrent.FutureTask.run(FutureTask.java:237)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243) 
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
        at java.lang.Thread.run(Thread.java:761) 
2018-11-04 16:47:27.716 966-989/? W/ActivityManager:   Force finishing activity uk.co.letsdelight.letsdelight/.MainActivity
2018-11-04 16:47:27.745 966-23481/? W/AES: Exception Log handling...

我还能做些什么来尝试解决这个问题,并可能使代码更健壮,以便我们在进一步更新时不会遇到问题?

【问题讨论】:

    标签: android apk auto-update


    【解决方案1】:

    第 1 步:将您的 Toast 替换为其他内容。您不能在后台线程上显示 Toast,这是错误消息告诉您的 (Can't create handler inside thread that has not called Looper.prepare())。假设您仍在使用AsyncTask,一个典型的解决方案是在AsyncTask 的字段中保留Exception,然后在onPostExecute() 中对其进行处理,因为这是在主应用程序线程上执行的.

    第 2 步:始终记录异常。至少,您应该登录到 LogCat。如果您已经集成了 ACRA、Crashlytics 或类似的解决方案,您应该采取措施确保您的异常也在那里得到报告。现在,您的catch试图显示Toast,这意味着您无法知道具体问题是什么(例如,缺乏连接性)。

    步骤#3:Android 7.0+ 上的一个特定问题是您不能很好地使用Uri.fromFile(),因为file Uri 值被禁止。在这些设备上,使用FileProvider 使APK 可供安装程序使用,并使用FileProvider.getUriForFile() 获取Uri 以放入您的Intent。不幸的是,在 Android 6.0 和更早版本的设备上,您不能使用 FileProvider,因为安装程序不支持 content Uri 值。因此,您需要检测您的版本(Build.VERSION.SDK_INT)并根据版本使用正确的Uri

    【讨论】:

    • 我添加了一些日志来跟踪文件下载的开始和结束。这些按预期记录。我还调整了catch 块,因此它在字段中捕获Exception 并记录Throwable.toString() - 但这不是写入LogCat。这向我表明,问题不在于更新代码,而在于要安装的 APK。但是如果我手动安装它,它工作正常!
    【解决方案2】:

    有时 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 发生在 AsyncTasks 中,因为您在后台线程中调用 execute。 您可以附加一个调试器并检查您是否在后台执行此 asyncTask。您可以使用 Evaluator 获取 Thread.currentThread().getId() 的值,如果它返回 1,则表示您在主线程上,如果不是,请尝试在应用程序的主线程中调用执行

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-19
      • 2014-04-11
      • 1970-01-01
      • 1970-01-01
      • 2011-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多