Android应用开发Permission理解
来源:互联网 发布:淘宝延长收货最长几天 编辑:程序博客网 时间:2024/06/03 11:33
Android的permission机制想必大家并不陌生。在开始主要内容之前,我们来简单回顾一下吧。
1.Android为每个应用程序分配一个唯一的UID,以确保每个应用程序有独立的空间,使它与其它应用程序分隔开来,避免其他应用程序进行非授权的访问。
2.Android可以为其几大组件定义permission,包括Activity, Service, ContentProvider, BroadCast Intent.
3.在manifest中定义或声明使用permission.
下面给一些例子,便于理解和使用上面说的几点:
1.声明自定义permission
<permission android:name=“com.example.perm.READ_INCOMING_MSG” android:label=“Read incoming messages from the EX service.” android:description=“Allows the app to access any messages received by the EX service. Any app granted this permission will be able to read all messages processed by the ex1 application.” android.protectionLevel=“dangerous” android:permissionGroup=“android.permission-group.PERSONAL_INFO” />
2.使用权限
<manifest xmlns:android=“http://schemas.android.com/apk/res/android” package=“com.example.testapps.test1”> ... <uses-permission android:name=“android.permission.INTERNET” /> ... </manifest>
3.为Activity添加permission
<activity android:name=“.Activity1” android.permission=“com.example.perm.START_ACTIVITY”> <intent-filter> ... </intent-filter> </activity>
添加后,只有声明使用 com.example.perm.START_ACTIVITY的应用才能启动此Activity.
4.为Service添加permission,类似于Activity。
<service android:name=“.MailListenerService” android:permission=“com.example.perm.BIND_TO_MSG_LISTENER” android:enabled=“true” android:exported=“true” <intent-filter></intent-filter> </service>
5.为ContentProvider添加permission,这个应用的最为广泛。
a.在provider中添加权限。我们添加了读权限和写权限。
<provider android:name=“com.example.test.app1.MailProvider” android:authorities=“com.example.test.app1.mailprovider” android:readPermission=“com.example.perm.DB_READ” android:writePermission=“com.example.perm.DB_WRITE”> </provider>
b.有时候我们需要主动grant权限给其他应用。
<provider android:name=“com.example.test.app1.MailProvider” android:authorities=“com.example.test.app1.mailprovider” android:readPermission=“com.example.perm.DB_READ” android:writePermission=“com.example.perm.DB_WRITE” android:grantUriPermission=“true”> </provider>
上面我们主动grant了整个provider的权限给其他应用。我们还可以只grant其中的某个子路径给其他应用。
<provider android:name=“com.example.test.app1.MailProvider” android:authorities=“com.example.test.app1.mailprovider” android:readPermission=“com.example.perm.DB_READ” android:writePermission=“com.example.perm.DB_WRITE”> <grant-uri-permission android:path=“/attachments/”> </provider>
c.在程序中动态的grant URI权限给Action接收者。
uri = “content://com.example.test.provider1/attachments/42”; Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(uri, “image/gif”); startActivity(intent);
d.在程序中动态的将权限grant给某一指定应用。
uri = “content://com.example.test.provider1/attachments/42”; Context.grantUriPermission(“com.example.test.app2”, uri,intent.FLAG_GRANT_READ_URI_PERMISSION);
6.为Broadcast添加permisson。
a.在发送Broadcast时指定permission
Intent bcastIntent = new Intent(MESSAGE_RECEIVED); context.sendBroadcast(bcastIntent, “com.example.perm.MSG_NOTIFY_RCV”);
b.在注册receiver时指定permission
IntentFilter intentFilter = new IntentFilter(MESSAGE_RECEIVED); UIMailBroadcastReceiver rcv = new UIMailBroadcastReceiver(); context.registerReceiver(rcv, intentFilter,“com.example.perm.MSG_NOTIFY_SEND”, null);
7.在程序中动态检查是否拥有某一权限(不鼓励使用)
int canProcess = checkCallingOrSelfPermission(“com.example.perm.READ_INCOMING_MSG”); if (canProcess != PERMISSION_GRANTED) throw new SecurityException();在我们使用权限的过程中,经常会碰到android:protectionLevel这个域。它称为permission level:
Android permissions fall into four levels:
Normal – These permissions cannot impart real harm to the user (e.g. change the wallpaper) and, while apps need to requestthem, they are automatically granted.
Dangerous – These can impart real harm (e.g. call numbers,open Internet connections, etc) and apps need to request them with user confirmation.
Signature – These are automatically granted to a requesting app. if that app is signed by the same certificate (so, developed by thesame entity) as that which declared/created the permission. This level is designed to allow apps that are part of a suite, or otherwise related, to share data.
Signature/System – Same as Signature, except that the system image gets the permissions automatically as well. This is designed for use by device manufacturers only.
当某一系统的provider权限被声明为signature时,我们第三方的应用程序是无法访问到的,但如果它grant了其中的某些子路径,那么这些子路径就可以访问。
在JellyBean中,我们看到DownloadProvider的ALL_ACCESS_DOWNLOADS权限被声明为signature保护方式,但幸运的是all_download这个子路径是被grant出来的。
所以第三方的应用程序是可以接收share intent来访问它的。那么下面就到了我们要重点讨论的问题:grant URI的有效期限问题。
Grant URI的有效期限
正如上面我们描述的情形,当我们拿到了DownloadProvider给我们的权限时(前提是我们注册了接收ACTION_SEND的activity),在我们的Activity创建时可以接收到
这个URI来进行一系列操作。下面给出一段测试代码:
HelloActivity.java package com.xm.permission; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class HelloActivity extends Activity { private Uri mUri; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); if (intent.getAction() == Intent.ACTION_SEND) { mUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); } if (mUri == null) { return; } InputStream inputStream; try { inputStream = getContentResolver().openInputStream(mUri); FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/test.bin")); int length; byte[] buffer = new byte[1440]; while ((length = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, length); } fileOutputStream.flush(); fileOutputStream.close(); inputStream.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xm.permission" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:label="@string/app_name" android:name=".HelloActivity" > <intent-filter > <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> <intent-filter android:label="@string/app_name" > <action android:name="android.intent.action.SEND" /> <data android:mimeType="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
运行上面的code,我们可以成功的写一个文件到SDCard上。也许这简单的不能再简单了,但我们的问题来了,看下面:
我们添加了另外一个activity:
package com.xm.permission; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; public class Hello2 extends Activity { private Uri mUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); mUri = intent.getData(); if (mUri == null) { return; } InputStream inputStream; try { inputStream = getContentResolver().openInputStream(mUri); FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/test23.bin")); int length; byte[] buffer = new byte[1440]; while ((length = inputStream.read(buffer)) != -1) { fileOutputStream.write(buffer, 0, length); } fileOutputStream.flush(); fileOutputStream.close(); inputStream.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
同时在AndroidManifest.xml中添加如下一句:
- <activity android:name=".Hello2"></activity>
并在HelloActivity.java中的catch语句后加上如下代码:
Intent intent2 = new Intent(HelloActivity.this, Hello2.class); intent2.setData(mUri); startActivity(intent2); finish();
再次运行,结果会怎么样?
答案是:可能抛出下面的异常:
E/AndroidRuntime(14582): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.xm.permission/com.xm.permission.Hello2}:java.lang.SecurityException: Permission Denial: reading com.android.providers.downloads.DownloadProvider uri content://downloads/all_downloads/1 from pid=14582, uid=10192requires android.permission.ACCESS_ALL_DOWNLOADS, or grantUriPermission()
明明之前有权限,怎么突然没有了呢?
这是因为我们添加了下面的code:
finish();// HelloActivity.java
当我们调用finish()方法结束HelloActivity后,权限也随之消失。如果我们添加如下code在HelloActivity.java中,就不会抛出异常:
Intent intent2 = new Intent(HelloActivity.this, Hello2.class); intent2.setData(mUri); startActivity(intent2);也就是说,当调用finish()以后,最初负责接收permission的Activity被释放,permission也一并被回收了。
所以我们要尽量在接收URI的activity中处理完所有操作。这里如果我们想存储这个URI到Database以备后用的话,也会出现权限的问题。所以,如果
这个资源需要在三方的程序中访问,最好是将它拷贝过来到SDCard,但要注意会有暴露用户隐私的风险。如果都是小文件,可以考虑拷贝到应用程序目录。
总结:当protectionlevel设置为signature时,动态Grant给第三方应用的permission不是一成不变的,它也有有效期限
转载自http://www.verydemo.com/demo_c89_i24835.html
- Android应用开发Permission理解
- 深入Android应用开发-透彻理解Permission
- Android开发 permission各权限的理解
- Android开发基础之permission
- android开发中的权限permission
- Android开发权限permission知识点
- Android开发-API指南-<permission>
- Android Permission的 protectLevel的理解
- android开发:Manifest.permission常用的权限
- Android开发-API指南-<grant-uri-permission>
- Android开发-API指南-<path-permission>
- Android开发-API指南-<permission-group>
- Android开发-API指南-<permission-tree>
- Android开发 adb命令提示:Permission denied
- Android开发使用权限permission积累
- Android 自定义应用permission 权限给其他应用方式
- 浅谈Android应用开发中一些概念的理解
- Android应用开发 推送理解析极光推送使用详解
- JavaScript获取文本框光标的像素位置
- Java中关于volatile和transient这两个关键字
- 推送
- Ubuntu下开启SSH服务
- 正则表达式
- Android应用开发Permission理解
- 4.6-二叉树的2个节点的第一个公共祖先节点
- Qt 使用当前系统没有的字体
- 启动tomcat报错:org.apache.catalina.loader.DevLoader
- ubuntu下jdk的安装与配置
- JQuery AJAX参数详解补充
- 如何创建Content Provider
- vim中对文本的选择
- Light Oj 1211 计算多个立方体重叠部分体积