Обновление APK - PullRequest
       7

Обновление APK

0 голосов
/ 04 ноября 2018

У нас есть внутреннее приложение, которое проверяет наличие обновлений при запуске. Он не выпущен в 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 всех ошибок и исключений!

Ниже приведен вывод logcat с моего устройства API 24 во время обновления после загрузки файла. Кроме указания на проблему с классом 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...

Что еще я могу сделать, чтобы попытаться решить эту проблему и, возможно, сделать код более надежным, чтобы у нас не было проблем с дальнейшими обновлениями?

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Иногда java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() происходит в AsyncTasks, потому что вы вызываете execute в фоновом потоке. Вы можете присоединить отладчик и проверить, выполняете ли вы этот asyncTask в фоновом режиме или нет. вы можете использовать Evaluator для получения значения Thread.currentThread().getId(), если он возвращает 1, это означает, что вы находитесь в главном потоке, если нет, попробуйте вызвать execute в главном потоке вашего приложения

0 голосов
/ 04 ноября 2018

Шаг # 1: замените ваш Toast чем-то другим. Вы не можете отобразить Toast в фоновом потоке, о чем говорит сообщение об ошибке (Can't create handler inside thread that has not called Looper.prepare()). Типичное решение, учитывая, что вы все еще используете AsyncTask, состоит в том, чтобы удерживать Exception в поле в AsyncTask, а затем сделать что-то с ним в onPostExecute(), как это выполняется в основном потоке приложения. .

Шаг № 2: Всегда регистрировать исключения. Как минимум, вы должны войти в LogCat. Если у вас есть интегрированные решения ACRA, Crashlytics или аналогичные, вы должны предпринять шаги для обеспечения того, чтобы о ваших исключениях также сообщалось там. В данный момент ваш catch блок only пытается показать 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 в зависимости от версии.

...