I'm trying to create an application that automatically downloads an apk from a specific server and install it on the system. My code for the installation looks like the following, but does not work.
File f = new File("/mnt/sdcard/download/", "Demo.apk");
Log.i("Demo", "f "+f.getAbsoluteFile());
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package_archive");
intent.addFlags(intent.FLAG_ACTIVITY_NEW_TASK);
m_context.startActivity(intent);
Do i need to give any rights in Manifest.xml for installation? I know that question has been asked before, but none of the answers have helped me so far.
This what I do in my case,
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path+"/<application_name>.apk")), "application/vnd.android.package-archive");
startActivity(intent);
And these are the permissions..
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Thanks for all help, made it work at last. I share my working code and working Manifest.xml.
package test.installer;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
public class InstallToolActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("Demo", "onCreate");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://"+"/mnt/sdcard/HelloWorld.apk"), "application/vnd.android.package-archive");
intent.addFlags(intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Manifext.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.installer"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="11" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.RESTART_PACKAGES"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:label="#string/app_name"
android:name=".InstallToolActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
//Fredrik
i also do
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
and my install lookd like this
intent.setDataAndType(Uri.parse("file://"+path), "application/vnd.android.package-archive");
my path is a String, like your f
You need to do this
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(f), "application/vnd.android.package-archive");
In your code, you have mentioned "package_archive", it should be "package-archive".
You would need the following permissions.
<uses-permission android:name="android.permission.INSTALL_PACKAGES"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
If your targetSdkVersion is equal or higher than 24, then you need to use FileProvider implementation for Android N and newer Android versions.
Here is the whole implementation:
// utility method
private void openAppInstaller(Context context, File toInstall) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", toInstall);
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent)
} else {
Uri apkUri = Uri.fromFile(toInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
Add provider FileProvider to AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
<application
...
<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>
</application>
</manifest>
And create provider_paths.xml under xml resources.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
</paths>
More info about FileProvider configuration you can read here and here.
All credits go to #just_user because my answer based on his reply.
Related
I am new to the broadcast receiver and implemented broadcast receiver dynamically as shown below
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mService=new StarterOnBoot();
registerReceiver(mService,filter);
in manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.autostartter">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.AutoStartTer">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/Theme.AutoStartTer.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".RuntimePermission"
android:label="#string/app_name"
android:theme="#style/Theme.AutoStartTer.NoActionBar">
</activity>
</application>
</manifest>
I have also created a button, by clicking who send broadcast manually as shown below
view.findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SCREEN_ON);
MainActivity.instance_main.sendBroadcast(intent);
}
});
Broadcast Service is
package com.example.autostartter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import java.util.logging.Handler;
public class StarterOnBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Broadcast Hit", Toast.LENGTH_SHORT).show();
if(intent.getAction().equals(Intent.CATEGORY_HOME))
{
Intent i=new Intent(context,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getAction().equals(Intent.ACTION_USER_UNLOCKED))
{
Intent i=new Intent(context,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
Intent i=new Intent(context,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
{
Intent i=new Intent(context,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED))
{
Intent i=new Intent(context,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
the broadcast works properly when the user unlocks the screen. However, when I click on the button the application crashes with the following exception
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.autostartter, PID: 30645
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.SCREEN_ON from pid=30645, uid=10245
at android.os.Parcel.createException(Parcel.java:2074)
at android.os.Parcel.readException(Parcel.java:2042)
at android.os.Parcel.readException(Parcel.java:1990)
at android.app.IActivityManager$Stub$Proxy.broadcastIntent(IActivityManager.java:5089)
at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1059)
at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:458)
at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:458)
at com.example.autostartter.FirstFragment$2.onClick(FirstFragment.java:44)
at android.view.View.performClick(View.java:7185)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7162)
at android.view.View.access$3500(View.java:819)
at android.view.View$PerformClick.run(View.java:27684)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7562)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:15351)
at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:15202)
at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:15991)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2051)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2799)
I have also acquired overlay permissions
Please ignore any mistake not directly related to this problem.
Add this permission to the Manifest file.
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
I am trying to update my app from outside Google Play, but I have an error, I have looked at everything and I cannot find a solution.
With the following 3 methods I hope to do the AutoUpdate:
private final String FILE_NAME = "app-release.apk";
public void checkStoragePermission(){
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
} else {
updateApp();}
}
private void updateApp() {
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", new File(this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + FILE_NAME));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 123: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
updateApp();
} else {
checkStoragePermission();
}
return;
}
}
}
My Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.jose.updateinapp">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
</manifest>
And the .xml for FileProvider
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="files_root"
path="Android/data/${applicationId}" />
<external-path
name="external_files"
path="." />
</paths>
The app that i'm attempting to install is the same but with versionCode 2 and versionName 2.0 instead of versionCode 1 and versionName 2.0
When executed this throws an error on the device: error parsing the package
Nothing comes out in the run console. And in the logcat the following errors appear:
E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri
content://com.jose.updateinapp.provider/external_files/Android/data/com.jose.updateinapp/files/Download/app-release.apk
from pid=16603, uid=10035 requires the provider be exported, or
grantUriPermission()
Error staging apk from content URI
java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri
content://com.jose.updateinapp.provider/external_files/Android/data/com.jose.updateinapp/files/Download/app-release.apk
from pid=16603, uid=10035 requires the provider be exported, or
grantUriPermission()
Any solution? Thank you!
Sorry,something missed in my head.
Try this:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="" />
<external-files-path
name="Download"
path="" />
</paths>
uri = FileProvider.getUriForFile(context,
"packgeName.provider",
new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "xxx.apk"));
intentInstall.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
just try it. it worked in my project..
private void updateApp() {
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", new File(this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/" + FILE_NAME));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//setFlags change addFlags
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
Can someone tell me, why my app can't create dirs?
Here is my Code:
package com.example.android.myapplication;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.os.Environment;
import java.io.File;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "meinordner");
if(!dir.exists()) {
boolean s = dir.mkdirs();
if(!s) {
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setMessage("could not create dir");
alert.show();
}
}
}
}
and my Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.myapplication" >
<uses-permission android:name="ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
when i execute the app, the alert is shown. I even tried to start the app when my phone is not connected to the computer and therfore the storage is not mounted somewhere else
First, change:
<uses-permission android:name="ANDROID.PERMISSION.WRITE_EXTERNAL_STORAGE"/>
to:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Second, change:
new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ File.separator + "meinordner");
to:
new File(Environment.getExternalStorageDirectory(), "meinordner");
I am stuggling to get my intent started on boot, basically the service is not appearing in my running or cached processes. I know since 3.1 you must have an activity that has run for the service to work, so this is what I have
MainActivity
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
public class StartActivity extends Activity {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Context context = getApplicationContext();
CharSequence text = "Updater Started";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
startService(new Intent(this,UpdaterService.class));
finish();
}
}
My intent
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class StartIntent extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, UpdaterService.class);
context.startService(myIntent);
CharSequence text = "Updater Started";
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
and finally my appmanifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.package.removed"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoDisplay">
<activity
android:name="com.package.removed.StartActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:enabled="true" android:name=".StartIntent" android:exported="false" />
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</application>
</manifest>
Basically my toast is never displayed, does anyone know what I have missed?
Your intent-filter is outside of the receiver. It should be like this:
<receiver android:enabled="true" android:name=".StartIntent" android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
I'm trying to get this to open an url when the icon is selected/clicked, but I get Syntax error on tokens, delete these tokens on the line String url =
String url = "http://www.google.co.uk/";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.openurl"
android:versionCode="1"
android:versionName="1.0" >
<application>
<activity android:name="OpenURL" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I've now got a bit further on this one but when I load the apk file the icon opens the browser with 2 windows - blank and the url. I;m also unable to use the back button to close the browser - it keeps opening the url. How can I correct these issues?
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name">
<activity
android:name="com.example.myapp.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.example.myapp;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String url = "http://www.google.co.uk";
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
}
Many thanks again!
This
String url = "http://www.google.co.uk/";
can never be the first line of a java file.
You file need a structure like:
package a.b.c; // optional
import java.util.List; // optional
public class ClassName { // mandatory
// your code
} // mandatory
If this fixes your error, you should consider reading a Java tutorial.
First of all add the permission for internet in your manifest:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
then your main should be like this:
public class Main extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.yourmainlayout);
Button button = (Button) findViewById(R.id.yourbuttonid);
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
String url = "http://www.google.co.uk/";
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(i);
}});
}
}