Android Apk在手机上安装失败问题解决

  • 之前在做App版本更新的时候,发现在5.0以上的手机上会出现安装失败崩溃的问题,之前一直好好的,突然出现这个问题,直接是蒙蔽状态,但又必须解决,所以只有对出现的问题进行跟踪,最后解决了,在这里做一下记录
问题1
  • APK在7.0以上手机若不设置FileProvider会直接安装崩溃并抛类似下面的异常,刚才是还以为是安装包路径写错了,后来才发现是在7.0中为了提高应用的安全性,引入私有目录被限制访问和StrictMode API(禁止向你的应用外公开file://url,若有一项包含文件file://url类型的Intent离开你的应用,则会抛出异常)

    android.os.FileUriExposedException: file:///XXX exposed beyond app through ClipData.Item.getUri() at android.os.StrictMode.onFileUriExposed(StrictMode.java:1799) at android.net.Uri.checkFileUriExposed(Uri.java:2346) at android.content.ClipData.prepareToLeaveProcess(ClipData.java:832) at android.content.Intent.prepareToLeaveProcess(Intent.java:8909)

  • 如何解决该问题了?

    • 针对这个问题google提供了FileProvider,使用它可以生成content://url 来替代file://url

      • 首先我们在res目录下新建一个xml的目录,然后创建一个file_paths.xml,然后配置你安装包目录,第一个参数可随意指定,第二参数为目录路径,需要准确指定,那它几种标签,可根据需要进行配置

在这里插入图片描述

					   	<files-path name="name" path="path" /> 物理路径相当于Context.getFilesDir() + /path/
						 
						<cache-path name="name" path="path" /> 物理路径相当于Context.getCacheDir() + /path/
						 
						<external-path name="name" path="path" /> 物理路径相当于Environment.getExternalStorageDirectory() + /path/
						 
						<external-files-path name="name" path="path" /> 物理路径相当于Context.getExternalFilesDir(String) + /path/
						 
						<external-cache-path name="name" path="path" /> 物理路径相当于Context.getExternalCacheDir() + /path/
  • 在清单文件中进行注册

       		           <provider
       		            android:name="android.support.v4.content.FileProvider"
       		            android:authorities="你的包名.fileprovider"
       		            android:exported="false"
       		            android:grantUriPermissions="true">
       		        <meta-data
       		            android:name="android.support.FILE_PROVIDER_PATHS"
       		            android:resource="@xml/file_paths" />
       		        </provider>
    
  • 代码

    	if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N) {//判读版本是否在7.0以上
    	       Uri apkUri = FileProvider.getUriForFile(this, "你的包名.fileprovider", apkFile);//在AndroidManifest中的android:authorities值
    	       Intent install = new Intent(Intent.ACTION_VIEW);
    	       install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    	       install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//添加这一句表示对目标应用临时授权该Uri所代表的文件
    	       install.setDataAndType(apkUri, "application/vnd.android.package-archive");
    	       startActivity(install);
    	} else{
    	       Intent install = new Intent(Intent.ACTION_VIEW);
    	       install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
    	       install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    	       startActivity(install);
    	}
    
问题2
  • Android为了进一步提高应用的安全性,设置了未知来源应用安装权限,根据用户的需求来是否允许安装不是从应用商店下载的apk,所以刚开始的时候,发现8.0.9.0的手机上即使设置FileProvider同样会安装失败,真是是崩溃,又的找google爸爸了。。。

  • 如何解决该问题了?

    • 在安装apk的时候我们需要检测我们是否有安装权限,若有我们在进行安装,若没有该权限,我们可以提示用户需要该权限,并且跳转到对应应用的应用权限管理中,让用户开启,之后再应用检测用户是拒绝了还是打开了,若打开了,表示我们有安装权限,此时我们才可以正常安装升级包了

      • 1.再清单文件中加入权限

             <!--安卓8.0打开apk安装更新-->
          <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
        
      • 检测是否允许安装未知来源的app

           @RequiresApi(api = Build.VERSION_CODES.O)
           public static boolean isHasInstallPermissionWithO(Context context){
               if (context == null){
                   return false;
               }
               return context.getPackageManager().canRequestPackageInstalls();
           }
        
    • 若返回true,直接启动Activity进行安装,反之,跳转到应用权限设置界面让用户去主动打开

       	    /**
       	     * 开启设置安装未知来源应用权限界面
       	     * @param context
       	     */
       	    @RequiresApi (api = Build.VERSION_CODES.O)
       	    public static void startInstallPermissionSettingActivity(Context context) {
       	        if (context == null){
       	            return;
       	        }
       	        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
       	        ((Activity)context).startActivityForResult(intent,REQUEST_CODE_APP_INSTALL);
                 }
      
    • 在用户设置后可通过onActivityResult()进行监测,判断是否打开了权限,不知道为什么我在这里获取到的resultCode不是Activity_OK,但权限的确是打开了,可以安装,所以比较建议再次检测一次应用是否有安装权限,若返回true,则开始安装更新包

       		       fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
       		          if (requestCode == AppUtils.REQUEST_CODE_APP_INSTALL) {
       		              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
       		                  val hasInstallPermission = AppUtils.isHasInstallPermissionWithO(mContext)
       		                  if (!hasInstallPermission) {
       		                      return
       		                  } else {
       		                      instaillApp()
       		                  }
       		              } else {
       		                  instaillApp()
       		              }
       		          }
       		    }
      }
       		              } else {
       		                  instaillApp()
       		              }
       		          }
       		    }
      
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值