Программно установить apk в Android 7/api24
Я пытаюсь получить мое приложение для автоматической установки apk. Это отлично работает для api <24. Но для 24 он терпит неудачу. Android реализовал дополнительную безопасность:
Для приложений, ориентированных на Android 7.0, платформа Android применяет политику StrictMode API, которая запрещает выставлять файлы://URI за пределами вашего приложения. Если намерение, содержащее URI файла, покидает ваше приложение, приложение выходит из строя с исключением FileUriExposedException.
Поэтому я попробовал это:
Uri myuri;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
myuri = Uri.parse("file://"+outapk);
} else {
File o = new File(outapk);
myuri = FileProvider.getUriForFile(con, con.getApplicationContext().getPackageName() + ".provider", o);
}
Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(myuri,"application/vnd.android.package-archive");
con.startActivity(promptInstall);
но получить фатальное исключение:
com.android.packageinstaller "Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{b42ee8a 6826:com.android.packageinstaller/u0a15} (pid=6826, uid=10015) that is not exported from uid 10066".
У меня есть export = true в моем манифесте.
Проблема заключается в том, что packageinstaller не может использовать контент://uri.
Есть ли способ разрешить приложению прогамматически устанавливать apk с api24?
Ответы
Ответ 1
Есть ли способ разрешить приложению прогамматически устанавливать apk с api24?
Добавьте addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
в promptInstall
, чтобы предоставить доступ для чтения к контенту.
У меня есть export = true в моем манифесте.
Не на вашем FileProvider
, так как это приведет к сбою вашего приложения.
Проблема заключается в том, что packageinstaller не может использовать контент://uri.
Нет, проблема в том, что вы не предоставили разрешение на установку установщика пакетов для чтения из этого Uri
. Если установщик пакетов не смог использовать схему content
, вы получили бы ActivityNotFoundException
.
Обратите внимание, однако, что только с Android 7.0 установщик пакетов начинает поддерживать content
. Раньше версии Android должны использовать file
.
Ответ 2
Для Oreo, добавить разрешение в AndroidManifast (в противном случае это просто молча не удается)
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
теперь добавь к тебе манифест
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
в каталоге xml добавить...
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." /></paths>
затем используйте эти коды, где вы хотите.
File directory = Environment.getExternalStoragePublicDirectory("myapp_folder");
File file = new File(directory, "myapp.apk"); // assume refers to "sdcard/myapp_folder/myapp.apk"
Uri fileUri = Uri.fromFile(file); //for Build.VERSION.SDK_INT <= 24
if (Build.VERSION.SDK_INT >= 24) {
fileUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", 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_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //dont forget add this line
context.startActivity(intent);
}
Ответ 3
Для Oreo добавьте разрешение в AndroidManifast
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Ответ 4
Добавить файл в res/xml
→ provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Добавьте этот код в AndroidManifest.xml
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.provider" <-- change this with your package name
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
запустите этот код для установки приложения или откройте
public void installApk(String file) {
Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider",new File(file));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
}
Ответ 5
просто выполните следующие шаги:
1- добавить следующее разрешение для манифеста:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
2- Добавить провайдера в манифест (как дочерний, как тег приложения):
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="tatcomputer.ir.libraryapp.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
</provider>
3- Добавить paths.xml в каталог xml:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files" path="." />
<external-files-path name="external_files" path="." />
<external-path name="external_files" path="." />
<cache-path name="cached_files" path="." />
<external-cache-path name="cached_files" path="." />
</paths>
4- покажите страницу установки apk, используя следующий код (обратите внимание, что в моем случае apk находится в корне моего телефона с именем tmp.apk:
String root = Environment.getExternalStorageDirectory().toString();
Uri fileUri24 = FileProvider.getUriForFile(App.applicationContext, BuildConfig.APPLICATION_ID + ".provider", new File(root + "/tmp.apk"));
Uri fileUri = Uri.fromFile(new File(root + "/tmp.apk"));
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= 24)
intent.setDataAndType(fileUri24, "application/vnd.android.package-archive");
else intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
App.applicationContext.startActivity(intent);
Ответ 6
Вот решение, которое я нашел
val newFile = File(dirPath, "$fileNameWithoutExtn.apk")
var fileUri = Uri.fromFile(newFile)
//use the fileProvider to get the downloaded from sdcard
if (Build.VERSION.SDK_INT >= 24) {
fileUri = FileProvider.getUriForFile([email protected], applicationContext.packageName + ".provider", newFile)
val intent=Intent(Intent.ACTION_VIEW)
intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
}else{
newFile.setReadable(true, false)
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
startActivity(intent)
}
и напишите в манифесте
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
а также установить разрешение
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
и в папке xml пути будут
<paths>
<external-path
name="external_files"
path="." />
</paths>
Ответ 7
Intall Apk автоматически
Intent intent1 = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent1.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent1.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" +filename)), "application/vnd.android.package-archive");
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Ответ 8
В моем случае на Android 8.0 проблема была в
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Подробнее о том, как получить это разрешение, Исключение & # 39; открыть не удалось: EACCES (В доступе отказано) & # 39; на Android