在android O

时间:2018-03-23 09:28:53

标签: android android-8.0-oreo

我尝试使用文件提供程序在我的应用程序中实现自动下载和安装apk。对于低于奥利奥的Android版本,它工作正常,但在Android 8.0及更高版本的设备上运行应用程序时出现问题。它一直很好,直到牛轧糖,但不适用于奥利奥。从服务器下载apk工作正常但无法安装新的apk。 这是我的代码。

File file, folder;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    Utility.checkPermissionCamera(Main2Activity.this);
    Utility.checkPermissionInstall(Main2Activity.this);
        String fileName = "AutoDownloadApplication.apk";
        folder = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString());
        Logger.e("FOLDER", " " + folder);
        file = new File(folder.getAbsolutePath(), fileName);
        Log.e("File ", "" + file);

        final Uri uri = FileProvider.getUriForFile(Main2Activity.this, BuildConfig.APPLICATION_ID + ".provider", file);
        Logger.e("Check URI ", "" + uri);
    if (Utility.checkPermissionCamera(Main2Activity.this)) {
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(StaticConstant.DOWNLOADAPK));
        request.setDescription("Downloading New Apk");
        request.setTitle(Main2Activity.this.getString(R.string.app_name));
        //set destination
        request.setDestinationInExternalFilesDir(Main2Activity.this, BuildConfig.APPLICATION_ID + ".provider", fileName);

        // get download service and enqueue file

            final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
            final long downloadId = manager.enqueue(request);
            //set BroadcastReceiver to install app when .apk is downloaded
            BroadcastReceiver onComplete = new BroadcastReceiver() {
                public void onReceive(Context ctxt, Intent intent) {

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
                    intent.setData(uri);
                    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    startActivity(intent);
                } else {
                    Intent install = new Intent(Intent.ACTION_VIEW);
                    install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    install.setDataAndType(uri,
                            manager.getMimeTypeForDownloadedFile(downloadId));
                    startActivity(install);
                }
                    unregisterReceiver(this);
                }
            };
            //register receiver for when .apk download is compete
            registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        }
}

清单文件:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="MyPackageName">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<permission
    android:name="android.permission.REQUEST_INSTALL_PACKAGES"
    android:protectionLevel="normal" />

<uses-permission
    android:name="android.permission.REQUEST_DELETE_PACKAGES"
    tools:ignore="ProtectedPermissions" />

<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="android.support.v4.content.FileProvider"
        android:authorities="MyPackageName.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

</application>

这是file_paths xml:

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path name="Download" path="Android/data/MyPackageName/files/Download"/>
</paths>

3 个答案:

答案 0 :(得分:1)

请首先在Manifest.xml中添加<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>权限。

如果SDK版本等于或大于26,我们应该检查getPackageManager().canRequestPackageInstalls()的结果。

代码如下:

private void checkIsAndroidO() {  
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {  
    boolean result = getPackageManager().canRequestPackageInstalls();  
    if (result) {  
      installApk();
    } else {  
      // request the permission 
      ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.REQUEST_INSTALL_PACKAGES}, INSTALL_PACKAGES_REQUESTCODE);  
    }  
  } else {
    installApk();  
  }  
}

@Override  
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {  
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);

  switch (requestCode) {  
    case INSTALL_PACKAGES_REQUESTCODE:  
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {  
        installApk();  
      } else {  
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);  
        startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES);  
      }  
    break;  
  }  
}

@Override  
protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
  super.onActivityResult(requestCode, resultCode, data); 

  switch (requestCode) {  
    case GET_UNKNOWN_APP_SOURCES:  
      checkIsAndroidO();  
      break;  

    default:  
      break;  
  }  
}

希望它能对您有所帮助。

答案 1 :(得分:0)

您可以从以下文章中详细了解FileProvider实现的详细信息:

https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/en

答案 2 :(得分:0)

JohnWatsonDev的效果很好! 只需输入一件事即可直接调用您的应用程序:

public class AdminModel
{
    public List<Notification> Notifications { get; set; }            
    public List<Places> Places { get; set; }

   public AdminModel()
   {
      Notifications = new List<Notification>();
      Places = new List<Places>();
   }
}

通话前

intent.setData(Uri.parse("package:" + getPackageName()));