Reputation: 740
I want to install new version of my app programmatically. with targetSdkVersion=23 app works fine and this is my code:
public class MainActivity extends AppCompatActivity {
private int PERMISSION_REQUEST_STORAGE = 0;
private DownloadController downloadController;
Button btn_download;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_download = findViewById(R.id.buttonDownload);
btn_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkStoragePermission();
}
});
}
public void checkStoragePermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
String url= getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/example.apk";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(Uri.parse("file://" + url), "application/vnd.android.package-archive");
String selfPackageName = getApplicationContext().getPackageName();
ComponentName componentName = intent.resolveActivity(getApplicationContext().getPackageManager());
String otherPackageName = (componentName != null ? componentName.getPackageName() : "");
if (MainActivity.this == null || !selfPackageName.equals(otherPackageName)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
startActivity(intent);
} else {
requestStoragePermission();
}
}
public void requestStoragePermission() {
ActivityCompat.requestPermissions(
MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_STORAGE);
}
}
but with targetSdkVersion=29 I heard that I have to use FileProvider. I used this instructure but unfortunately it dosent open my apk to install. this is my res=>xml=>file_provider_paths.xml
<?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>
my manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mysms">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET"/>
<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>
<receiver android:name=".service.OnComplete" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_provider_paths" />
</provider>
</application>
</manifest>
my mainActivity
public class MainActivity extends AppCompatActivity {
private int PERMISSION_REQUEST_STORAGE = 0;
private DownloadController downloadController;
Button btn_download;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_download = findViewById(R.id.buttonDownload);
btn_download.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkStoragePermission();
}
});
}
public void checkStoragePermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
File file = new File(getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/example.apk");
Uri uri = FileProvider.getUriForFile(getApplicationContext(), "com.example.myapp", file);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setData(Uri.fromFile(file));
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.setClassName("com.example.myapp", "com.example.myapp.MainActivity");
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
ClipData clipData = new ClipData(new ClipDescription("Meshes", new String[]{ClipDescription.MIMETYPE_TEXT_URILIST}), new ClipData.Item(uri));
install.setClipData(clipData);
startActivity(install);
} else {
requestStoragePermission();
}
}
public void requestStoragePermission() {
ActivityCompat.requestPermissions(
MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_STORAGE);
}
}
I get this error
2019-12-17 00:46:38.035 32020-32020/com.example.myapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.mysms, PID: 32020
android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.example.myapp/files/Download/example.apk exposed beyond app through Intent.getData()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799)
at android.net.Uri.checkFileUriExposed(Uri.java:2346)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8933)
at android.content.Intent.prepareToLeaveProcess(Intent.java:8894)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1517)
at android.app.Activity.startActivityForResult(Activity.java:4224)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
at android.app.Activity.startActivityForResult(Activity.java:4183)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
at android.app.Activity.startActivity(Activity.java:4507)
at android.app.Activity.startActivity(Activity.java:4475)
at com.example.mysms.MainActivity.checkStoragePermission(MainActivity.java:107)
at com.example.mysms.MainActivity$3.onClick(MainActivity.java:76)
at android.view.View.performClick(View.java:5610)
at android.view.View$PerformClick.run(View.java:22265)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Upvotes: 1
Views: 1707
Reputation: 3659
It seems the problem is that you set wrong uri to intent data:
install.setData(Uri.fromFile(file));
You need to set uri which was created with FileProvider:
Uri uri = FileProvider.getUriForFile(getApplicationContext(), "com.example.myapp", file);
install.setData(uri);
The same is done in the instruction you have found:
val contentUri = FileProvider.getUriForFile(
context,
BuildConfig.APPLICATION_ID + PROVIDER_PATH,
File(destination)
)
val install = Intent(Intent.ACTION_VIEW)
install.data = contentUri
Upvotes: 1