前言:今天突然想起来,前几天,一个在京东的同学,给我打电话,说他在吃饭时与一个技术大牛聊天,他说他android开发已经两年多了,不想再做android了,没什么挑战性了。当时大牛问了他几个问题,一个没答上来。然后,那人说,小伙子,你现在还处于不知道你不知道的阶段,再加把劲吧。然后,乖乖回去写代码。对于我这样一个还处在android入门阶段的人来讲,到达他这个程度已经是望尘莫及了,看来我还要再加把劲,从今天开始,每写一篇博客开头送给大家一句话,送给大家,也写给自己。
人生最可怕的,是比你优秀的人却比你更努力。
(加油,永远不要觉得别人望尘莫及,要做的,只是每天进步一点点)
一、概述
首先,我先讲一下,为什么需要有权限这个东东;
权限有两个作用:
其一:防止其它程序随便调用。
其二:能够在安装程序时,显式的给用户看,当前要安装的这个程序要用到哪个功能。这个是最重要的,试想,如果你装一个斗地主游戏,却看到要用到打电话、发短信的功能,便可以判定这个程序里面可能包含恶意代码,还是不装为好。
下面以打电话为例,来讲解一下系统对权限的要求:
一般情况下,要调用打电话的Activity,代码是这样写的:
Uri uri = Uri.parse("tel:12345678");
Intent intent = new Intent(Intent.ACTION_CALL, uri);
startActivity(intent);
如果我们此时直接执行,会出现下面的错误:
ERROR/AndroidRuntime: java.lang.SecurityException: Permission Denial:
starting Intent { act=android.intent.action.CALL dat=tel:12345678 cmp=com.android.phone/.OutgoingCallBroadcaster }
......
requires android.permission.CALL_PHONE
说的是需要CALL_PHONE的访问权限,这个权限是Android系统自带的phone应用里定义的权限:
......
<uses-permission android:name="android.permission.CALL_PHONE" />
......
<activity android:name="OutgoingCallBroadcaster"
android:permission="android.permission.CALL_PHONE"
android:theme="@android:style/Theme.NoDisplay"
android:configChanges="orientation|keyboardHidden">
<!-- CALL action intent filters, for the various ways
of initiating an outgoing call. -->
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="voicemail" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CALL" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/phone" />
<data android:mimeType="vnd.android.cursor.item/phone_v2" />
<data android:mimeType="vnd.android.cursor.item/person" />
</intent-filter>
</activity>
......
想要使用此功能,必须在我们的AndroidManifest.xml文件中声明使用此权限:
<application ...>
...
</application>
<uses-permission android:name="android.permission.CALL_PHONE"/>
这就是要告诉系统,我们的程序要用到打电话的功能。所以当用户安装程序时,系统只需要遍历AndroidManifest.xml文件就能知道我们需要访问哪些外部程序,即需要哪些程序的权限,比如打电话、发短信等,并以列表的形式告诉用户,当前你要安装的程序要用到哪些权限,以便用户决定确定安装,还是取消安装。
二、自定义权限
我们写两个应用,一个Test_Permission,一个客户端:Test_Perssion_Client;我们给Test_Permission加上访问权限,然后在客户端直接调Test_Permission的Activity;
首先是新建工程Test_Permission,然后添加访问权限;
添加访问权限的方法,我这里采用图形化工具的方法,在AndroidManifest.xml中,下面的Tab栏,有一栏叫Permissions,选中-》切到权限管理界面,选择Add按钮,增加一个权限;界面如下:
右边栏设置新增Permission的各项属性,Name和Protection level(风险等级)是必须的,其它项都可不填;写好之后,Ctrl + S 保存
其中的各项参数意义如下:摘自《Pro Android 3》中文版
在设定上面的参数后,代码中生成了下面几行代码:
<permission
android:name="harvic.permission.STARTMYPERSSION"
android:label="Start My Permission"
android:protectionLevel="normal" >
</permission>
所以,现在的AndroidManifest.xml为:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_permission"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<!-- 声明一个权限 -->
<permission
android:name="harvic.permission.STARTMYPERSSION"
android:label="Start My Permission"
android:protectionLevel="normal" >
</permission>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
上面,我们只是声明了一个权限,但到底哪个Activity要用这个权限,还不知道。其实这就跟声明一个变量一样,一个变量在声明之后,就存在在类中了,但不用的话就一点意义没有!一样的道理。
下面,我们创建一个Activity,命名为:PerssionActivity
PerssionActivity的XML代码为:将TextView显示的文字改为here it is,来表明已经进入到这个Activity中了;
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.test_permission.PerssionActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="here it is" />
</RelativeLayout>
然后在AndroidManifest.xml中添加上我们上面生成的访问权限:
<!-- 为Activity应用已定义的权限 -->
<activity
android:name=".PerssionActivity"
android:label="@string/title_activity_perssion"
android:permission="harvic.permission.STARTMYPERSSION" >
<intent-filter>
<action android:name="android.intent.action.MYPERSSION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
这里有两点注意:
1、添加访问权限是使用:android:permission;
2、因为我们要从外部访问PerssionActivity,所以我们必需要为其添加action和category,
<intent-filter>
<action android:name="android.intent.action.MYPERSSION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
这两个是必不可少的,其中action我们可以对其随意命名,在外部,我们可以通过传递这个action来隐式启动这个Activity,有关隐式启动Activity的问题,参看《intent详解(一)》和《intent详解(二)》
不管隐式启动还是显式启动,无论是从内部还是从外部启动这个activity,都必须要加上action和category这两个参数才行,不然根本启动不了。
到此,这个应用就建好了,下面我们就要另建一个应用,来调这个PerssionActivity了。
新建一个工程:Test_Perssion_Client;
首先为其添加访问权限:即
<uses-permission android:name="harvic.permission.STARTMYPERSSION"/>
所以总体的AndroidManifest.xml代码为:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test_perssion_client"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="harvic.permission.STARTMYPERSSION"/>
</manifest>
然后在布局文件中,添加一个Btn,单击时跳转用,XML布局代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.test_perssion_client.MainActivity" >
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="permission跳转"/>
</RelativeLayout>
最后是Java代码了:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn=(Button)findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//启动方法一:显示启动
Intent intent = new Intent();
// 表示希望启动com.example.test_permission包中的com.example.test_permission.MainActivity
intent.setClassName("com.example.test_permission", "com.example.test_permission.PerssionActivity");
//启动方法二:隐式启动,通过action匹配
// Intent intent = new Intent("android.intent.action.MYPERSSION");
startActivity(intent);
}
});
}
}
上面有两种启动PerssionActivity的方法,一个显式启动,一个隐式启动,在上面的《Intent详解》中都有讲到,这里就不再重复说了。
下面看效果:
点击之后跳转到PerssionActivity
问答环节:
问题:我在Test_Permission工程中另加一个Activity来让外部启动,为什么不能直接使用MainActivity从外部启动呢,非要多此一举?
答:其实我刚开始也是直接使用MainActivity多个外部启动的,但如果给MainActivity添加上访问权限后,你会发现,它自己都启动不起来了,不知道为什么会产生这么蛋疼的问题,所以只有另加一个Activity来演示了,如果有哪位仁兄知道为什么,敬请告知。
问题:从外部访问需要权限,那在应用程序内部访问还需要添加权限访问吗?
答:不需要,试试就知道了,在我上传的源码中,当点击hello world时,会跳转到Perssion Activity,而我并没有在AndroidManifest.xml中添加
<uses-permission android:name="harvic.permission.STARTMYPERSSION"/>
截图如下:
启动MainActivity 点击“hello world”实现内部跳转
源码下载地址:http://download.csdn.net/detail/harvic880925/7786463
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/38683625 谢谢!