How can I open an App using it own background service - xamarin

I'm creating Xamarin.Forms App and it has a service that runs in the background monitoring if any messages arrive. If a message arrives, the service should open the App.
I tried to open the App using Intent (Dependency Service) and I also tried using Xamarin.Essentials. Neither way worked.
My last attempt was with Xamarin.Essentials and gave the following error:
[Error][1]
[1]: https://i.stack.imgur.com/5jPGf.png
This is my code using Intent (Dependency Service):
//Intent (Dependency Service)
string teste = "com.saferit.saferproject";
openAppManager = DependencyService.Get<IAppHandler>();
openAppManager.Initialize(teste);
openAppManager.LaunchApp();
[enter image description here][2]
[2]: https://i.stack.imgur.com/lLx3g.png
This is my native code for Android
public void LaunchApp()
{
Intent intent = new Intent();
intent.SetClassName(Package, "activity");
intent.AddFlags(ActivityFlags.NewTask);
Xamarin.Forms.Forms.Context.StartActivity(intent);
}
[Complete Native Code][3]
[3]: https://i.stack.imgur.com/G4zOV.png
This is my AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.saferit.saferproject" android:installLocation="preferExternal">
<uses-sdk android:minSdkVersion="27" android:targetSdkVersion="29" />
<!--<application android:label="SaferProject.Android"></application>-->
<application android:label="com.saferit.saferproject" android:icon="#drawable/logo">
<activity android:icon="#drawable/logo" android:label="com.saferit.saferproject" android:name="com.saferit.saferproject">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.saferit.saferproject" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
This is my attempt using Xamarin.Essential:
//Xamarin.Essentials
var appname = "com.saferit.saferproject://";
var supportsUri = await Launcher.CanOpenAsync(appname);
if (supportsUri)
await Launcher.OpenAsync(appname);
Looking for here at stackoverflow I found this question:
Open Notification list page when user clicks on navigation
I tried to implement it on my App but I also couldn't get it to work.
In all three cases the errors are very similar.
I think the problem is in the configuration of the URI of my App.
Can someone help me?

Related

How to configure my manifes in Xamarin for Android V12

My current manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.cecop.cecop" android:installLocation="auto" android:versionCode="132" android:versionName="14.00">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="31" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:label="cecop" android:icon="#drawable/cecop">
<!--Especifique el número de versión de Google Play Services en el manifiesto y la clave de Google Maps V2 API. -->
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBLH0HotP0r5yfuX8xFESZhM5TS0PcluKs" />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<!-- Needed for Android >= Nougat for file access -->
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.cecop.cecop.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
<service android:name="com.cecop.cecop.ServicioSegundoPlano" android:exported="true"></service>
</application>
</manifest>
In the service and main activity I have this attributes
[Service(Exported = true, Name = "com.cecop.cecop.ServicioSegundoPlano")]
public class ServicioStartForeground : Service
{
...
}
[Activity(Label = "Cecop", Icon = "#drawable/icon", Theme = "#style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{...
}
As I write in the manifest so you don't get the error in the publication on Google Play?
You have uploaded an APK or Android App Bundle that has an activity, an alias of activity, a service or an emission receiver with atnts filter, but without establishing the Android property: exported. This file cannot be installed on Android 12 or later versions.
You don't have to define anything in AndroidManifest.xml if you are using the [Service] attribute. Xamarin generates this for you.
The only change you need to make on Android 12, is that you need to add whether a Service is exported or not. Default should be false unless you need to access it from another App than yours.
If you are using something like Xamarin.Essentials or other libraries that also contain services, make sure they are up to date and also follow these rules about adding Exported property on their services.

Android: Failed to find configured root that contains /data/data/com.app.myapp/files/myfile.pdf

I have a PDF file I download from an API and save to internal storage using Environment.SpecialFolder.MyDocuments. When I attempt to open the file I get the error in the title, Failed to find configured root that contains /data/data/com.app.myapp/files/myfile.pdf.
Code that saves files:
var filePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
System.IO.File.WriteAllBytes(filePath, fileBytes);
LaunchIntent(filePath);
Code where error occurs:
public static void LaunchIntent(string fileLocation)
{
// now create an activity which points to the file
var localPath = global::Android.Net.Uri.Parse(fileLocation).Path;
File javaFile = new File(localPath);
//error occurs at below code
var filePath = global::Android.Support.V4.Content.FileProvider.GetUriForFile(
CrossCurrentActivity.Current.Activity,
CrossCurrentActivity.Current.Activity.PackageName + ".fileprovider",
javaFile);
var actionView = new Intent(Intent.ActionView);
actionView.AddFlags(ActivityFlags.GrantReadUriPermission);
var extension = localPath.Substring(localPath.LastIndexOf('.') + 1);
var mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(extension);
actionView.SetDataAndType(filePath, mimeType);
CrossCurrentActivity.Current.Activity.StartActivity(actionView);
}
My file paths file:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external" path="." />
<external-files-path name="external_files" path="." />
<cache-path name="cache" path="." />
<external-cache-path name="external_cache" path="."/>
</paths>
According to your description, you pdf is saved in internal storage, Provider path for a specific path as followings:
<files-path/> --> Context.getFilesDir()
<cache-path/> --> Context.getCacheDir()
<external-path/> --> Environment.getExternalStorageDirectory()
<external-files-path/> --> Context.getExternalFilesDir(String)
<external-cache-path/> --> Context.getExternalCacheDir()
<external-media-path/> --> Context.getExternalMediaDirs()
You can refer to: https://developer.android.com/reference/androidx/core/content/FileProvider
So change your resources/xml/file_paths.xml
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
<files-path name="internal_files" path="." />
</paths>
And adding a provider in the AndroidManifest.xml file Application tag.
<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"></meta-data>
</provider>
</application>

Need help debugging exception error - Unable to get provider. Missing android.support.FILE_PROVIDER_PATHS

I am getting the exception error: 'Unable to get provider androidx.core.content.FileProvider: java.lang.IllegalArgumentException: Missing android.support.FILE_PROVIDER_PATHS meta-data
Here is a bit of my code:
public void SendMMSMessage()
{
Android.Telephony.SmsManager smsMessage = Android.Telephony.SmsManager.Default;
IList<string> divideContents = smsMessage.DivideMessage("I auto sent this message to you! No typing here!!!!!");
string filePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures) + "/TestPic.jpg";
byte[] sendPDUData = GetMMSPDUData("11111111111", filePath, "Hey this image was sent from my phone using code! No typing here");
if (sendPDUData != null)
{
SendMMSData(sendPDUData);
}
}
public byte[] GetMMSPDUData(string DestinationNumber, string AudioFilePath, string smsMessage)
{
byte[] pduData = null;
try
{
SendReq sendReq = new SendReq();
sendReq.AddTo(new EncodedStringValue(DestinationNumber));
PduBody pduBody = new PduBody();
// Add text message data to message
PduPart txtPart = new PduPart();
txtPart.SetData(Encoding.ASCII.GetBytes(smsMessage));
txtPart.SetContentType(new EncodedStringValue("text/plan").GetTextString());
txtPart.SetName(new EncodedStringValue("Message").GetTextString());
pduBody.AddPart(txtPart);
// Add image data
// TODO: Later, this will be audio file. But image file for testing
PduPart imgPart = new PduPart();
byte[] sampleImageData = System.IO.File.ReadAllBytes(AudioFilePath);
imgPart.SetData(sampleImageData);
imgPart.SetContentType(new EncodedStringValue("image/jpg").GetTextString());
imgPart.SetFilename(new EncodedStringValue(System.IO.Path.GetFileName(AudioFilePath)).GetTextString());
pduBody.AddPart(imgPart);
// Now create body of MMS
sendReq.Body = pduBody;
// Finally, generate the byte array to send to the MMS provider
PduComposer composer = new PduComposer(sendReq);
pduData = composer.Make();
}
catch(Exception ex)
{
// TODO: Do something here
}
return pduData;
}
public bool SendMMSData(byte[] PDUData)
{
Context CTX = Android.App.Application.Context;
Android.Telephony.SmsManager sm = Android.Telephony.SmsManager.Default;
Random rnd = new Random();
try
{
string cacheFilePath = System.IO.Path.Combine(CTX.CacheDir.AbsolutePath, "send." + "sendMe" + ".dat");
System.IO.File.WriteAllBytes(cacheFilePath, PDUData);
Java.IO.File testFile = new Java.IO.File(cacheFilePath);
string authString = CTX.PackageName + ".fileprovider";
if (System.IO.File.Exists(cacheFilePath))
{
Android.Net.Uri contentURI = AndroidX.Core.Content.FileProvider.GetUriForFile(CTX, CTX.PackageName + ".fileprovider", testFile);
// Android.Net.Uri contentURI = Android.Net.Uri.FromFile(testFile).Au
/* Android.Net.Uri contentURI = (new Android.Net.Uri.Builder())
.Authority(authString)
.Path(cacheFilePath)
.Scheme(ContentResolver.SchemeContent)
.Build();
*/
/*
* = (new Android.Net.Uri.Builder())
.Authority(ctx.PackageName + ".fileprovider")
.Path(cacheFilePath)
.Scheme(ContentResolver.SchemeContent)
.Build();
*/
PendingIntent pendingIntent = PendingIntent.GetBroadcast(CTX, 0, new Intent(CTX.PackageName + ".WAP_PUSH_DELIVER"), 0);
sm.SendMultimediaMessage(CTX, contentURI, null, null, null);
}
}
catch(Exception ex)
{
String exString = ex.ToString();
return false;
}
return true;
}
Also, here is my Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.janinesafety2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:label="janinesafety2.Android">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.suport.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths"
/>
</provider>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
<uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
</manifest>
and my Provider_path
<?xml version="1.0" encoding="utf-8" ?>
<paths>
<external-path
name="external_file"
path="./"
/>
</paths>
I have used these as resources to assist me in debugging:
androidx FILE_PROVIDER_PATHS
Unable to get provider androidx.core.content.FileProvider: java.lang.IllegalArgumentException: Missing android.support.FILE_PROVIDER_PATHS meta-data?
And unfortuntaly, I am still having issues with the expection. From what I can tell I am doing the exact thing everyone is saying.
Is there anyone there that can take a second a look at my code? Maybe I missed something.
Thank you.
You could refer to the code below.
1.Add the following to your AndroidManifest.xml inside the tags. YOUR_APP_PACKAGE_NAME must be set to your app package name.
<application>
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="#xml/file_paths"></meta-data>
</provider>
</application>
2.Add a new folder called xml into your Resources folder and add a new XML file called file_paths.xml. Add the following code:
<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." />
<external-path name="external" path="." />
<external-files-path name="external_files" path="." />
<cache-path name="cache" path="." />
<external-cache-path name="external_cache" path="." />
<files-path name="files" path="." />
</paths>
I added all the tags. You could get from the link below.
FileProvider - IllegalArgumentException: Failed to find configured root

How to use Activity attribute android:showForAllUsers in Xamarin?

The attribute is not implemented in Xamarin. This mean I can't declare it as an attribute of my Activity Class like it should:
[Activity(Label = "#string/app_name", Theme = "#style/MainTheme.StopAlarm", LaunchMode = Android.Content.PM.LaunchMode.SingleTask, ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait, NoHistory = true)]
public class StopAlarmActivity : Activity
{
...
}
There's no ShowForAllUsers option.
The other option is to edit Properties => AndroidManifest.xml and add the activity manually like this:
<activity
android:name=".StopAlarmActivity"
android:label="#string/app_name"
android:theme="#style/MainTheme.StopAlarm"
android:showForAllUsers="true">
</activity>
But once I compile the final AndroidManifest.xml file contains two declarations, the manually added and the compiled one from the class declaration.
<activity android:name=".StopAlarmActivity" android:label="#string/app_name" android:theme="#style/MainTheme.StopAlarm" android:showForAllUsers="true"></activity>
<activity android:label="#string/app_name" android:launchMode="singleTask" android:noHistory="true" android:screenOrientation="portrait" android:theme="#style/MainTheme.StopAlarm" android:name="md5e24228758d0205525e724fe958bff865.StopAlarmActivity" />
That said, it looks like the only option is to edit the compiled AndroidManifest.xml file after each compilation. Which is a major breach for problems.
Any other way to accomplish it where I don't need to rely on remembering it every time I compile the app?
On your Activity attribute, applied a Name to avoid the MD5-based Java class auto-naming:
[Activity(Name = "com.sushihangover.MainActivity")]
In your manifest use the same fully-qualified name (no abbreviated dot notation) with the attributes you wish to apply to this activity:
<activity
android:name="com.sushihangover.MainActivity"
android:showForAllUsers="true"
android:icon="#mipmap/icon"
android:label="MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: All the attributes for this Activity need to be added within the manifest, not the Activity class attribute.
The final manifest entries will be merged correctly:
<activity android:name="com.sushihangover.MainActivity" android:showForAllUsers="true" android:icon="#mipmap/icon" android:label="MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Programmatically install an apk in Android 7 / api24

I am trying to get my app to automatically install an apk. This works fine for api<24. But for 24, it is failing. Android has implemented extra security:
For apps targeting Android 7.0, the Android framework enforces the StrictMode API policy that prohibits exposing file:// URIs outside your app. If an intent containing a file URI leaves your app, the app fails with a FileUriExposedException exception.
So I tried this:
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);
but get a fatal exception:
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".
I have export=true in my manifest.
The problem seems to be that packageinstaller cannot use a content:// uri.
Are there any ways to allow an app to progammatically install an apk with api24?
Are there any ways to allow an app to progammatically install an apk with api24?
Add addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) to your promptInstall setup, to grant read access to the content.
I have export=true in my manifest.
Not on your FileProvider, as that would cause your app to crash.
The problem seems to be that packageinstaller cannot use a content:// uri.
No, the problem is that you did not grant permission to the package installer to read from that Uri. Had the package installer been unable to use a content scheme, you would have gotten an ActivityNotFoundException.
Note, though, that it is only with Android 7.0 that the package installer starts supporting content. Earlier versions of Android have to use file.
For Oreo, Add permission in AndroidManifast (Otherwise it just silently fails)
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
now add to you'r 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/provider_paths"/>
</provider>
in xml directory add...
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="." /></paths>
then use these codes where you want.
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);
}
For Oreo,
Add permission in AndroidManifast
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Here is the solution I have found
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(this#SettingAcitivity, 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)
}
and write in 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/paths"/>
and also set the permission
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
and in xml folder paths will be
<paths>
<external-path
name="external_files"
path="." />
</paths>
Add file in 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>
Add this code in 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>
run this code for install your app or open
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);
}
simply do the following steps:
1- add the following permission to manifest:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
2- Add provider to manifest (as child as application tag):
<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- Add paths.xml to xml directory:
<?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- show install apk page using following code (note that in my case apk is in root of my phone named 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);
Intall Apk automatically
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);
In my case on android 8.0 problem was in
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
More detailed how to get this permission Exception 'open failed: EACCES (Permission denied)' on Android
Update in 2022
You can't use internal storage to install an APK. You have to use External Storage instead.
And this is for people looking at how to install step-by-step APK on a remote Android device. Also, the tutorial has a NodeJS Server implementation.
Remote install for Android app using APK

Resources