web-dev-qa-db-ja.com

プログラムでAPKをAndroid 7 / api24にインストールします

アプリでAPKを自動的にインストールしようとしています。これはapi <24で正常に機能します。しかし、24の場合は失敗しています。 Androidは追加のセキュリティを実装しています:

Android 7.0をターゲットとするアプリの場合、Androidフレームワークは、アプリ外にfile:// URIを公開することを禁止するStrictMode APIポリシーを適用します。ファイルを含むインテントの場合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がcontent:// uriを使用できないことです。

アプリがapi24を使用してプログラムでAPKをインストールできるようにする方法はありますか?

13
elsie

アプリがapi24を使用してプログラムでAPKをインストールできるようにする方法はありますか?

addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)promptInstall設定に追加して、コンテンツへの読み取りアクセスを許可します。

マニフェストにexport = trueがあります。

FileProviderではありません。アプリがクラッシュするためです。

問題は、packageinstallerがcontent:// uriを使用できないことです。

いいえ、問題は、そのUriからの読み取りをパッケージインストーラーに許可していないことです。パッケージインストーラーがcontentスキームを使用できなかった場合、ActivityNotFoundExceptionを取得することになります。

ただし、Android 7.0の場合のみ、パッケージインストーラーがcontentをサポートし始めることに注意してください。以前のバージョンのAndroidはfile

13
CommonsWare

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);
}
6
smartmob

オレオの場合は、AndroidManifastで権限を追加します

<uses-permission Android:name="Android.permission.REQUEST_INSTALL_PACKAGES"/>
3
Dwivedi Ji

これが私が見つけた解決策です

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)
                        }

とマニフェストに書き込む

<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>
1
Mudassir Khan

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);
0
Narendra.kr

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);
    }
0
Ahmad Aghazadeh

私の場合Android 8.0に問題がありました

<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>

この権限を取得する方法の詳細 Androidでの例外「open failed:EACCES(Permission denied)」

0
Andrii

次の手順を実行するだけです。

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);
0
farhad.kargaran