当前位置: 首页 > news >正文

网站如何伪静态知名网站建设加盟合作

网站如何伪静态,知名网站建设加盟合作,文章页模板wordpress,cms 网站模板高版本的android对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用FileProvider去实现,这篇博客来一起了解下它的实现原理。 首先我们要明确一点,FileProvider就是一个ContentProvider,所以需要在AndroidManifest.xml里面对它进行声明: provideran…高版本的android对文件权限的管控抓的很严格,理论上两个应用之间的文件传递现在都应该是用FileProvider去实现,这篇博客来一起了解下它的实现原理。 首先我们要明确一点,FileProvider就是一个ContentProvider,所以需要在AndroidManifest.xml里面对它进行声明: providerandroid:nameandroidx.core.content.FileProviderandroid:authoritiesme.demo.fileprovider.providerandroid:exportedfalseandroid:grantUriPermissionstruemeta-dataandroid:nameandroid.support.FILE_PROVIDER_PATHSandroid:resourcexml/file_path / /provider 和普通的ContentProvider不一样的是他多了一个android.support.FILE_PROVIDER_PATHS的meta-data指定了一个xml资源: ?xml version1.0 encodingutf-8? paths xmlns:androidhttp://schemas.android.com/apk/res/androidroot-path nameroot path /files-path namefiles pathimages/ /cache-path namecache path /external-path nameexternal path /external-files-path nameexternal-files path /external-cache-path nameexternal-cache path /external-media-path nameexternal-media path / /paths 文件URI 这个xml的作用在于为文件生成URI,root-path、files-path、cache-path这些标签代表父路径: root-path : File(/) files-path : Context.getFilesDir() cache-path : context.getCacheDir() external-path : Environment.getExternalStorageDirectory() external-files-path : ContextCompat.getExternalFilesDirs(context, null)[0] external-cache-path : ContextCompat.getExternalCacheDirs(context)[0] external-media-path : context.getExternalMediaDirs()[0] path属性代表子路径,name代表为父路径/子路径起的名字, files-path namefiles pathimages/ / 例如上面配置代表的就是我们为 new File(context.getFilesDir(), images/) 这个路径起了个名字叫做files val filesDir File(context.getFilesDir(), images/) val uri FileProvider.getUriForFile(this, me.linjw.demo.fileprovider.provider, File(filesDir, test.jpg)) // uri就是把filesDir的路径转换files,然后加上content://me.linjw.demo.fileprovider.provider // 即 content://me.linjw.demo.fileprovider.provider/files/test.jpg 从FileProvider的源码里面就能看到这部分的转换逻辑:private static final String TAG_ROOT_PATH root-path; private static final String TAG_FILES_PATH files-path; private static final String TAG_CACHE_PATH cache-path; private static final String TAG_EXTERNAL external-path; private static final String TAG_EXTERNAL_FILES external-files-path; private static final String TAG_EXTERNAL_CACHE external-cache-path; private static final String TAG_EXTERNAL_MEDIA external-media-path;...int type; while ((type in.next()) ! END_DOCUMENT) {if (type START_TAG) {final String tag in.getName();final String name in.getAttributeValue(null, ATTR_NAME);String path in.getAttributeValue(null, ATTR_PATH);File target null;if (TAG_ROOT_PATH.equals(tag)) {target DEVICE_ROOT;} else if (TAG_FILES_PATH.equals(tag)) {target context.getFilesDir();} else if (TAG_CACHE_PATH.equals(tag)) {target context.getCacheDir();} else if (TAG_EXTERNAL.equals(tag)) {target Environment.getExternalStorageDirectory();} else if (TAG_EXTERNAL_FILES.equals(tag)) {File[] externalFilesDirs ContextCompat.getExternalFilesDirs(context, null);if (externalFilesDirs.length 0) {target externalFilesDirs[0];}} else if (TAG_EXTERNAL_CACHE.equals(tag)) {File[] externalCacheDirs ContextCompat.getExternalCacheDirs(context);if (externalCacheDirs.length 0) {target externalCacheDirs[0];}} else if (Build.VERSION.SDK_INT Build.VERSION_CODES.LOLLIPOP TAG_EXTERNAL_MEDIA.equals(tag)) {File[] externalMediaDirs context.getExternalMediaDirs();if (externalMediaDirs.length 0) {target externalMediaDirs[0];}}if (target ! null) {strat.addRoot(name, buildPath(target, path));}} }...private static File buildPath(File base, String... segments) {File cur base;for (String segment : segments) {if (segment ! null) {cur new File(cur, segment);}}return cur; } 查询的时候就只需要从strat里面找到文件路径最匹配的name即可。 打开文件 有了这个uri之后我们就能通过Intent将它传给其他应用,并配置Intent.FLAG_GRANT_READ_URI_PERMISSION或者Intent.FLAG_GRANT_WRITE_URI_PERMISSION为其他应用设置读写权限: val uri FileProvider.getUriForFile(this, me.linjw.demo.fileprovider.provider, file) val intent Intent() intent.data uri intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.setClassName(me.linjw.demo.fileprovider.recv, me.linjw.demo.fileprovider.recv.MainActivity) startActivity(intent) 其他应用拿到这个uri就可以通过ContentResolver.openInputStream打开文件流: val inputStream intent.data?.let { contentResolver.openInputStream(it) } 或者有时候我们希望通过String传递uri的时候可以提前使用Context.grantUriPermission为指定的包名申请权限,然后接收端Uri.parse去解析出Uri来操作文件: // 发送端 val uri FileProvider.getUriForFile(this, me.linjw.demo.fileprovider.provider, file) grantUriPermission(me.linjw.demo.fileprovider.recv, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)val intent Intent() intent.putExtra(uri, uri.toString()) intent.setClassName(me.linjw.demo.fileprovider.recv, me.linjw.demo.fileprovider.recv.MainActivity) startActivity(intent)// 接收端 val uri Uri.parse(intent.getStringExtra(uri)) val inputStream contentResolver.openInputStream(uri) Uri操作文件的原理实际上就是通过请求我们之前声明的me.linjw.demo.fileprovider.provider这个ContentProvider,让它给我们去打开文件: // FileProvider.java public ParcelFileDescriptor openFile(NonNull Uri uri, NonNull String mode)throws FileNotFoundException {// ContentProvider has already checked granted permissionsfinal File file mStrategy.getFileForUri(uri);final int fileMode modeToMode(mode);return ParcelFileDescriptor.open(file, fileMode); } 也就是说文件权限的校验实际上只发生在打开的阶段.其他应用虽然没有权限打开我们的文件,但是我们可以在ContentProvider里面帮它打开然后返回文件描述符,给其他应用去读写。 系统应用使用FileProvider的坑 项目中有个系统应用需要向其他应用传的文件,于是把FileProvider加上,然后发现其他应用还是没有权限。从日志里面看是说这个FileProvider并没有从UID 1000里暴露出来: 02-13 06:52:28.921 4292 4292 E AndroidRuntime: Caused by: java.lang.SecurityException: Permission Denial: opening provider androidx.core.content.FileProvider from ProcessRecord{806d30d 4292:me.linjw.demo.fileprovider.recv/u0a53} (pid4292, uid10053) that is not exported from UID 1000 由于这个UID 1000太显眼所以尝试将系统签名去掉发现权限就正常了,实锤是系统签名的原因。 查看出现异常的时候的日志,发现了下面的打印: 02-13 06:52:28.486 863 1393 W UriGrantsManagerService: For security reasons, the system cannot issue a Uri permission grant to content://me.linjw.demo.fileprovider.provider/root/data/user/0/me.linjw.demo.fileprovider/files/test.txt [user 0]; use startActivityAsCaller() instead 在代码里面搜索关键字,发现系统应用需要在源码里面配置FileProvider的authorities: // https://cs.android.com/android/platform/superproject//android-13.0.0_r29:frameworks/base/services/core/java/com/android/server/uri/UriGrantsManagerService.java// Bail early if system is trying to hand out permissions directly; it // must always grant permissions on behalf of someone explicit. final int callingAppId UserHandle.getAppId(callingUid); if ((callingAppId SYSTEM_UID) || (callingAppId ROOT_UID)) {if (com.android.settings.files.equals(grantUri.uri.getAuthority())|| com.android.settings.module_licenses.equals(grantUri.uri.getAuthority())) {// Exempted authority for// 1. cropping user photos and sharing a generated license html// file in Settings app// 2. sharing a generated license html file in TvSettings app// 3. Sharing module license files from Settings app} else {Slog.w(TAG, For security reasons, the system cannot issue a Uri permission grant to grantUri ; use startActivityAsCaller() instead);return -1;} } 直接传递ParcelFileDescriptor 从原理上看FileProvider实际就是打开文件的ParcelFileDescriptor传给其他应用使用,那我们能不能直接打开文件然后将ParcelFileDescriptor直接通过Intent传给其他应用呢? val intent Intent() intent.putExtra(fd , ParcelFileDescriptor.open(file, MODE_READ_ONLY)) intent.setClassName(me.demo.fileprovider.recv, me.linjw.demo.fileprovider.recv.MainActivity) startActivity(intent) 答案是不行: 02-15 20:27:24.200 16968 16968 E AndroidRuntime: Process: me.linjw.demo.fileprovider, PID: 16968 02-15 20:27:24.200 16968 16968 E AndroidRuntime: java.lang.RuntimeException: Not allowed to write file descriptors here 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.nativeWriteFileDescriptor(Native Method) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.writeFileDescriptor(Parcel.java:922) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.ParcelFileDescriptor.writeToParcel(ParcelFileDescriptor.java:1110) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.writeParcelable(Parcel.java:1953) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.writeValue(Parcel.java:1859) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.writeArrayMapInternal(Parcel.java:1024) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1620) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Bundle.writeToParcel(Bundle.java:1304) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.os.Parcel.writeBundle(Parcel.java:1093) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.content.Intent.writeToParcel(Intent.java:11123) 02-15 20:27:24.200 16968 16968 E AndroidRuntime: at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java: 2298) 原因在于Instrumentation的execStartActivity启动Activity前会调用Intent.prepareToLeaveProcess最终调用到Bundle.setAllowFds(false)不允许传递ParcelFileDescriptor: // https://cs.android.com/android/platform/superproject//android-13.0.0_r29:frameworks/base/core/java/android/app/Instrumentation.java public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {...intent.prepareToLeaveProcess(who);... }// https://cs.android.com/android/platform/superproject//android-13.0.0_r29:frameworks/base/core/java/android/content/Intent.java public void prepareToLeaveProcess(Context context) {final boolean leavingPackage;if (mComponent ! null) {leavingPackage !Objects.equals(mComponent.getPackageName(), context.getPackageName());} else if (mPackage ! null) {leavingPackage !Objects.equals(mPackage, context.getPackageName());} else {leavingPackage true;}prepareToLeaveProcess(leavingPackage); }/*** Prepare this {link Intent} to leave an app process.** hide*/ public void prepareToLeaveProcess(boolean leavingPackage) {setAllowFds(false);... }public void setAllowFds(boolean allowFds) {if (mExtras ! null) {mExtras.setAllowFds(allowFds);} } 一开始我想通过反射去强行调用setAllowFds(true),但是发现这个方法被限制了,需要系统权限才能调用: Accessing hidden method Landroid/os/Bundle;-setAllowFds(Z)Z (max-target-o, reflection, denied) 只能另谋出路,由于ParcelFileDescriptor实现了Parcelable,所以我们可以通过传递Binder的方式迂回的去传递: // aidl interface IFileDescriptorsProvider {ParcelFileDescriptor get(); }// 发送端 val fileProvider object : IFileDescriptorsProvider.Stub() {override fun get(): ParcelFileDescriptor {return ParcelFileDescriptor.open(file, MODE_READ_ONLY)} } val intent Intent() val bundle Bundle().apply { putBinder(fileProvider, fileProvider) } intent.putExtras(bundle) intent.setClassName(me.demo.fileprovider.recv, me.demo.fileprovider.recv.MainActivity) startActivity(intent)// 接收端 val text intent.extras?.getBinder(fileProvider)?.let { it -val fd IFileDescriptorsProvider.Stub.asInterface(it).get()AssetFileDescriptor(fd, 0, -1).createInputStream().use { it.bufferedReader().readLine() } } 也可以封装成服务端service提供接口客户端通过aidl连接服务端后调用服务端接口返回ParcelFileDescriptor对象去获取文件。
文章转载自:
http://www.morning.zxfr.cn.gov.cn.zxfr.cn
http://www.morning.4r5w91.cn.gov.cn.4r5w91.cn
http://www.morning.mcndn.cn.gov.cn.mcndn.cn
http://www.morning.nzwp.cn.gov.cn.nzwp.cn
http://www.morning.rdzlh.cn.gov.cn.rdzlh.cn
http://www.morning.swsrb.cn.gov.cn.swsrb.cn
http://www.morning.brrxz.cn.gov.cn.brrxz.cn
http://www.morning.hbtarq.com.gov.cn.hbtarq.com
http://www.morning.fhddr.cn.gov.cn.fhddr.cn
http://www.morning.mhmdx.cn.gov.cn.mhmdx.cn
http://www.morning.muniubangcaishui.cn.gov.cn.muniubangcaishui.cn
http://www.morning.rynq.cn.gov.cn.rynq.cn
http://www.morning.kbfzp.cn.gov.cn.kbfzp.cn
http://www.morning.mkpkz.cn.gov.cn.mkpkz.cn
http://www.morning.hcqpc.cn.gov.cn.hcqpc.cn
http://www.morning.bbgn.cn.gov.cn.bbgn.cn
http://www.morning.nmfwm.cn.gov.cn.nmfwm.cn
http://www.morning.pzqnj.cn.gov.cn.pzqnj.cn
http://www.morning.dqcpm.cn.gov.cn.dqcpm.cn
http://www.morning.wnkbf.cn.gov.cn.wnkbf.cn
http://www.morning.ydhmt.cn.gov.cn.ydhmt.cn
http://www.morning.tfzjl.cn.gov.cn.tfzjl.cn
http://www.morning.plnry.cn.gov.cn.plnry.cn
http://www.morning.jwdys.cn.gov.cn.jwdys.cn
http://www.morning.tyjnr.cn.gov.cn.tyjnr.cn
http://www.morning.gblrn.cn.gov.cn.gblrn.cn
http://www.morning.nqmdc.cn.gov.cn.nqmdc.cn
http://www.morning.fjscr.cn.gov.cn.fjscr.cn
http://www.morning.swbhq.cn.gov.cn.swbhq.cn
http://www.morning.qpqcq.cn.gov.cn.qpqcq.cn
http://www.morning.vvbsxm.cn.gov.cn.vvbsxm.cn
http://www.morning.bxyzr.cn.gov.cn.bxyzr.cn
http://www.morning.wpcfm.cn.gov.cn.wpcfm.cn
http://www.morning.lztrt.cn.gov.cn.lztrt.cn
http://www.morning.jfgmx.cn.gov.cn.jfgmx.cn
http://www.morning.xnkb.cn.gov.cn.xnkb.cn
http://www.morning.mmplj.cn.gov.cn.mmplj.cn
http://www.morning.mxdhy.cn.gov.cn.mxdhy.cn
http://www.morning.dgfpp.cn.gov.cn.dgfpp.cn
http://www.morning.kehejia.com.gov.cn.kehejia.com
http://www.morning.xnkh.cn.gov.cn.xnkh.cn
http://www.morning.wjjxr.cn.gov.cn.wjjxr.cn
http://www.morning.ygbq.cn.gov.cn.ygbq.cn
http://www.morning.ljtwp.cn.gov.cn.ljtwp.cn
http://www.morning.tgyzk.cn.gov.cn.tgyzk.cn
http://www.morning.rzcbk.cn.gov.cn.rzcbk.cn
http://www.morning.skksz.cn.gov.cn.skksz.cn
http://www.morning.rjrlx.cn.gov.cn.rjrlx.cn
http://www.morning.spxk.cn.gov.cn.spxk.cn
http://www.morning.dkslm.cn.gov.cn.dkslm.cn
http://www.morning.txzqf.cn.gov.cn.txzqf.cn
http://www.morning.qbgdy.cn.gov.cn.qbgdy.cn
http://www.morning.lcbnb.cn.gov.cn.lcbnb.cn
http://www.morning.kxsnp.cn.gov.cn.kxsnp.cn
http://www.morning.fcrw.cn.gov.cn.fcrw.cn
http://www.morning.xyrss.cn.gov.cn.xyrss.cn
http://www.morning.jfbrt.cn.gov.cn.jfbrt.cn
http://www.morning.djmdk.cn.gov.cn.djmdk.cn
http://www.morning.rcjqgy.com.gov.cn.rcjqgy.com
http://www.morning.bbtn.cn.gov.cn.bbtn.cn
http://www.morning.rbqlw.cn.gov.cn.rbqlw.cn
http://www.morning.ssxlt.cn.gov.cn.ssxlt.cn
http://www.morning.xjqkh.cn.gov.cn.xjqkh.cn
http://www.morning.ksqzd.cn.gov.cn.ksqzd.cn
http://www.morning.lsjtq.cn.gov.cn.lsjtq.cn
http://www.morning.nmwgd.cn.gov.cn.nmwgd.cn
http://www.morning.zmzdx.cn.gov.cn.zmzdx.cn
http://www.morning.kgsws.cn.gov.cn.kgsws.cn
http://www.morning.xhgcr.cn.gov.cn.xhgcr.cn
http://www.morning.znsyn.cn.gov.cn.znsyn.cn
http://www.morning.xbnkm.cn.gov.cn.xbnkm.cn
http://www.morning.jfbpf.cn.gov.cn.jfbpf.cn
http://www.morning.bpmtr.cn.gov.cn.bpmtr.cn
http://www.morning.jgncd.cn.gov.cn.jgncd.cn
http://www.morning.rbjf.cn.gov.cn.rbjf.cn
http://www.morning.jcrlx.cn.gov.cn.jcrlx.cn
http://www.morning.flxgx.cn.gov.cn.flxgx.cn
http://www.morning.zqzhd.cn.gov.cn.zqzhd.cn
http://www.morning.datadragon-auh.cn.gov.cn.datadragon-auh.cn
http://www.morning.rbyz.cn.gov.cn.rbyz.cn
http://www.tj-hxxt.cn/news/237136.html

相关文章:

  • 做排名出租网站邯郸做小程序的网络公司
  • 网站怎样盗链图片网络营销推广策划方案
  • 做托福的网站大连网站制作.net
  • 佛山网站建设公司哪家性价比高呼家楼做网站的公司哪家好
  • 济南专业做公司网站的机构公司注册资金实缴后多久可以取出
  • 大连六兄弟网站建设深圳免费网站制作哪个好
  • 深圳做网站的公司有没有便宜的注册代理
  • 网站运营维护的基本工作多用户自助建站
  • 成都市成华区建设路商务中心网站怎么用手机开发app
  • wordpress网站工具栏wordpress自定义分类无法显示
  • 建设行业公司网站公明做企业网站
  • 玮科网站建设知道抖音视频是怎么做的网站嘛
  • 网站鼠标悬停动态效果用模块做网站
  • 哪里有网站制作平台wordpress dopt
  • 互联网站开发python 网站开发 pdf
  • qq排名优化网站免费查企业电话网站
  • 个人如果做网站赚钱吗成都市建设领域网站咨询电话
  • 浙江省住房和城乡建设厅网站查询WordPress 整个网站导出
  • 定制旅游网站有哪些网站开发软件三剑客
  • jsp网站首页怎么做常见网站图标
  • 网泰网站建设手机网站建设图
  • 怎么建设淘宝客网站中小企业名录
  • 企业门户网站国内外研究现状用wordpress建立专业网站视频教程
  • 网站的侧边栏怎么做近期的新新闻
  • 网站建设步骤及分工互联网技术英文
  • dw网站模板免费下载哪些做展架图的网站好
  • 网吧网站怎么做的园林绿化
  • 网站备案系统源码做seo网站图片怎么优化
  • 购物网站难做吗查网站是否正规
  • 资源分享类网站模板做网站运营用什么配置电脑