Автообновление приложения [android]

202
25 марта 2019, 06:30

Вылетает ошибка на андроиде 7+ и 8+ (6 и ниже - все как надо) при автообновлении приложения. Код:

private void updateApp(String url) {
    String destination = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/";
    String fileName = url.split("/")[url.split("/").length-1].trim();

    destination += fileName;
    uri = Uri.parse("file://" + destination);
    //Delete update file if exists
    File file = new File(destination);
    if (file.exists())
        if (file.delete()) {
            Log.e("upd", fileName + "was deleted");
        } else {
            Log.e("upd", fileName + "not exists");
        }

    // get download service and enqueue file
    final DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    //set downloadmanager
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
    request.setTitle(fileName);
    //set destination
    request.setDestinationUri(uri);
    if (manager != null) manager.enqueue(request);
    //set BroadcastReceiver to install app when .apk is downloaded
    BroadcastReceiver onComplete = new BroadcastReceiver() {
        public void onReceive(Context ctxt, Intent intent) {
            if (Objects.requireNonNull(intent.getAction()).equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Intent install = new Intent(Intent.ACTION_VIEW);
                install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                install.setDataAndType(uri, "application/vnd.android.package-archive");
                context.startActivity(install);
                context.unregisterReceiver(this);
            }
        }
    };
    //register receiver for when .apk download is compete
    context.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}

Ошибка:

FATAL EXCEPTION: main
Process: com.kinotor.tiar, PID: 9198
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.DOWNLOAD_COMPLETE flg=0x10 pkg=com.kinotor.tiar (has extras) } in com.kinotor.tiar.kinotor.updater.UpdateDialog$1@fcf1a81
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_51267(LoadedApk.java:1305)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.$m$0(Unknown Source:4)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.run(Unknown Source:0)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6541)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
 Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Download/app.apk exposed beyond app through Intent.getData()
    at android.os.StrictMode.onFileUriExposed(StrictMode.java:1958)
    at android.net.Uri.checkFileUriExposed(Uri.java:2348)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:9766)
    at android.content.Intent.prepareToLeaveProcess(Intent.java:9720)
    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1742)
    at android.app.Activity.startActivityForResult(Activity.java:5153)
    at android.app.Activity.startActivityFromFragment(Activity.java:5129)
    at android.app.Activity$HostCallbacks.onStartActivityFromFragment(Activity.java:7602)
    at android.app.Fragment.startActivity(Fragment.java:1179)
    at android.app.Fragment.startActivity(Fragment.java:1158)
    at com.kinotor.tiar.kinotor.updater.UpdateDialog.startIntent(UpdateDialog.java:145)
    at com.kinotor.tiar.kinotor.updater.UpdateDialog.access$000(UpdateDialog.java:37)
    at com.kinotor.tiar.kinotor.updater.UpdateDialog$1.onReceive(UpdateDialog.java:124)
    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_51267(LoadedApk.java:1295)
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.$m$0(Unknown Source:4) 
    at android.app.-$Lambda$FilBqgnXJrN9Mgyks1XHeAxzSTk.run(Unknown Source:0) 
    at android.os.Handler.handleCallback(Handler.java:789) 
    at android.os.Handler.dispatchMessage(Handler.java:98) 
    at android.os.Looper.loop(Looper.java:164) 
    at android.app.ActivityThread.main(ActivityThread.java:6541) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767) 

И все (может даже слишком) права прописал в манифесте

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>

Hellp (((( И как еще можно сделать автообновление? В AsyncTask закачать файл через httcClient?

Answer 1

Начиная с Андроид 7 нельзя через Intent передавать файлы по протоколу file:// - даже звучит странно, но "жираф большой - ему видней" .
Нужно теперь применять провайдер, самое простое для такого случая FileProvider.

В Вашем случае можно попробовать другой вариант: не указывать в DownloadManager.Requestпуть сохранения файла - он будет загружен в дефолтную папку загрузок, а "правильную" ссылку на него можно получить как-то так:

if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equalsIgnoreCase(intent.getAction())) {
    DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
    Query query = new Query();
    query.setFilterById(id);
    Cursor cursor = dm.query(query);
    if (cursor != null && cursor.moveToFirst()) {
        if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
            String localUri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
            Intent install = new Intent(Intent.ACTION_VIEW);
            install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            install.setDataAndType(localUri, "application/vnd.android.package-archive");
            // и наверное нужно передать разрешение
            install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            context.startActivity(install);
            context.unregisterReceiver(this);
        }
        cursor.close();
    }
READ ALSO
Импорт файла CVS в базу данных. Java

Импорт файла CVS в базу данных. Java

Прошу не судить строгоПишу код- учусь

187
Цикл for и разновидность

Цикл for и разновидность

Друзья! Нашел такой цикл в книге:

185
System.in.read() или всё же Scanner?

System.in.read() или всё же Scanner?

Заметил во многих книгах используется: Systemin

157
Операторы или Циклы?

Операторы или Циклы?

В книгах вижу часто вот такое: оператор if, оператор switch и тдТак же вижу слова аля: в этом цикле if или в этом цикле for работает так и вот так

175