Решения, предоставленные на этот вопрос, все применимы к targetSdkVersion
с 23 и ниже. Однако для Android N, т. Е. Уровня API 24 и выше, они не работают и аварийно завершают работу со следующим исключением:
android.os.FileUriExposedException: file:///storage/emulated/0/... exposed beyond app through Intent.getData()
Это связано с тем, что, начиная с Android 24, Uri
для адресации загруженного файла изменился. Например, установочный файл с именем appName.apk
, хранящийся в основной внешней файловой системе приложения с именем пакета com.example.test
, будет иметь вид
file:///storage/emulated/0/Android/data/com.example.test/files/appName.apk
для API 23
и ниже, тогда как что-то вроде
content://com.example.test.authorityStr/pathName/Android/data/com.example.test/files/appName.apk
для API 24
и выше.
Более подробную информацию об этом можно найти здесь , и я не собираюсь проходить через это.
Чтобы ответить на вопрос для targetSdkVersion
из 24
и выше, необходимо выполнить следующие шаги:
Добавьте следующее в AndroidManifest.xml:
<application
android:allowBackup="true"
android:label="@string/app_name">
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.authorityStr"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
</provider>
</application>
2. Добавьте следующий файл paths.xml
в папку xml
на res
в src, main:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="pathName"
path="pathValue"/>
</paths>
pathName
- это то, что показано в приведенном выше примере содержимого, а pathValue
- это фактический путь в системе.
Было бы неплохо поставить "." (без кавычек) для pathValue в приведенном выше, если вы не хотите добавлять дополнительные подкаталоги.
Напишите следующий код для установки apk с именем appName.apk
в основной внешней файловой системе:
File directory = context.getExternalFilesDir(null);
File file = new File(directory, fileName);
Uri fileUri = Uri.fromFile(file);
if (Build.VERSION.SDK_INT >= 24) {
fileUri = FileProvider.getUriForFile(context, context.getPackageName(),
file);
}
Intent intent = new Intent(Intent.ACTION_VIEW, fileUri);
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.setDataAndType(fileUri, "application/vnd.android" + ".package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
activity.finish();
При записи в личный каталог вашего приложения во внешней файловой системе также не требуется никаких разрешений.
Я написал библиотеку автообновления здесь , в которой я использовал выше.