I am using File provider for installing downloaded APK using Google Package installer in Android TV But always stuck on Package Parsing Error.
The same code base is working fine on android Mobile phone OS but not on Android TV. To note, Mine is a system application and have all the required permissions like REQUEST_INSTALL_PACKAGES, READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE but still no luck.
Can any folk please help me if this is a known bug on Android TV or there is something special need my attention.
Checklist:
1. Provider cross-checked with authority to grantURIPermissions
<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>
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="."/>
<files-path
name="data"
path="."/>
<cache-path
name="cache"
path="." />
<external-path name="external_download" path="Download"/>
<external-files-path name="Download" path="Download/" />
val uri = FileProvider.getUriForFile(this#MainActivity, BuildConfig.APPLICATION_ID+".provider", file)
val intent = Intent(Intent.ACTION_VIEW)
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
intent.setDataAndType(uri, "application/vnd.android.package-archive")
val resInfoList = context?.packageManager?.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY)
resInfoList?.let {
for (res in resInfoList) {
val packageName = res.activityInfo.packageName
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
context.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
}
}
startActivity(intent)
internal fun getDownloadFileLoc(context: Context): String {
val fileDir = "${Environment.getExternalStorageDirectory()}/download"
val fileName = context.getString(R.string.apk_name)
return "$fileDir/$fileName"
}
I get a warning that permission denial for provider. Please tell me if I have to provide some specific information.
Related
I want to open files from my Android app (Cordova) in external apps with write access, so they can make changes. (Example: sign a PDF).
The files to open are under external-files-path and can be opened. Unfortunately, the changes are not saved.
Since Android 11 (API Level 30) the file:// calls don't work anymore (with disableDeathOnFileUriExposure hack). With the content:// call I get no write access passed to the app.
I use the following logic to open the file (the coding is from https://github.com/pwlin/cordova-plugin-file-opener2):
File file = new File(fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
Context context = cordova.getActivity().getApplicationContext();
Uri path = FileProvider.getUriForFile(context, cordova.getActivity().getPackageName() + ".fileOpener2.provider", file);
intent.setDataAndType(path, contentType);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (openWithDefault) {
cordova.getActivity().startActivity(intent);
} else {
cordova.getActivity().startActivity(Intent.createChooser(intent, "Open File in..."));
}
AndroidManifest.json
<provider android:authorities="${applicationId}.fileOpener2.provider" android:exported="false" android:grantUriPermissions="true" android:name="io.github.pwlin.cordova.plugins.fileopener2.FileProvider">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/opener_paths" />
</provider>
opener_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="files" path="." />
<cache-path name="cache" path="." />
<external-files-path name="external-files" path="." />
<external-cache-path name="external-cache" path="." />
<external-path name="external" path="." />
</paths>
I have created a html page with tables that lists android apks.
I also have an APK which displays the html page, when clicking the download button it downloads the chosen APK... Perfect!
What I want to do is once the download is complete it requests to install the application.
I've tried a few things but it's too much for me to do, would anyone mind helping for some beer tokens,
Thanks
You can add a BroadcastReceiver as a callback when your download completes , and then call the following method inside that callback-
public static void installapk(File apkFile, Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (apkFile.exists()) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
install.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
Uri apkUri =
FileProvider.getUriForFile(context, "com.yourcompany.yourapp.fileprovider", apkFile);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(install);
} else {
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(Uri.fromFile(apkFile),
"application/vnd.android.package-archive");
context.startActivity(install);
}
} else {
System.out.println("apk doesnot exist.");
}
}
}
Don't forget to add this permission in your AndroidManifest.xml file -
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
You also need to create a fileprovider authority in your AndroidManifest.xml -
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
Then Create a new xml File inside res/xml folder named file_paths.xml and paste this code -
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<files-path
name="files"
path="." />
</paths>
Happy Coding!
I am using FileProvider to install apk from my app. Followed many stackoverflow questions but still facing this issue
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.tssi.myapptour/files/download/myapp_newSigned.apk
My provider in manifest
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.tssi.myapptour.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
my file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="download" path="download/" />
<!-- <external-path name="download" path="Android/data/com.tssi.myapptour/files/download/" />-->
</paths>
And my code for calling apk
String strApkToInstall = "myapp_newSigned.apk";
File fileApkToInstall = new File(getExternalFilesDir("download"), strApkToInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri fileUri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider",
fileApkToInstall);
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
Your file is in getExternalFilesDir(). That does not match files-path in your FileProvider metadata. Either:
Switch to getFilesDir() (a much better solution from a security standpoint), or
Switch to external-files-path
See the FileProvider documentation for more about the mapping between filesystem locations and metadata entries.
I am trying to install apk after it has been downloaded by the download manager. I am using a broadcast to get the message after download completes. This is my code below:-
FileProvider: Installing APK. There was an error parsing the package.
val file = File(getExternalFilesDir("Download"), "/playlist/update.apk")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val apkUri = FileProvider.getUriForFile(this#MainActivity, BuildConfig.APPLICATION_ID + ".provider", file)
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
intent.data = apkUri
intent.flags= Intent.FLAG_GRANT_READ_URI_PERMISSION
this#MainActivity.startActivity(intent)
} else {
val apkUri = Uri.fromFile(file)
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(apkUri, "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
this#MainActivity.startActivity(intent)
}
Manifest:-
<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/filepaths" />
</provider>
filespath.xml :-
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="Download" path="Download/" />
</paths>
I am downloading the apk in "Downloads/playlist/" dir. I saw this same problem - here. However I have can't seem to get it working from that solution. I also checked the apk by installing it myself and it gets installed without any errors. Please help.
My app crashed when open camera in Android 7.0
File captureFilePath = new File(cachePath, CommonUtil.getDateTimeForFileName(System.currentTimeMillis())+".jpg");
Uri uri = Uri.fromFile(captureFilePath);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, REQUEST_CAPTURE_IMAGE);
CAPTURE_IMAGE_PATH = captureFilePath.getAbsolutePath();
If your targetSdkVersion >= 24, then we have to use FileProvider class to give access to the particular file or folder to make them accessible for other apps.
1) First Add a FileProvider tag in AndroidManifest.xml under tag as below:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
<provider
android:name=".GenericFileProvider"
android:authorities="${applicationId}.my.package.name.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"/>
</provider>
</application>
</manifest>
2) Then create a provider_paths.xml file in res/xml folder. Folder may be needed to created if it doesn't exist.
<paths>
<external-path name="external_files" path="."/>
</paths>
3) Now edit your activity class file as below:
Uri uri = Uri.fromFile(captureFilePath);
to
Uri uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID, captureFilePath);