7.1 内容提供器简介
内容提供器(Content Provider)主要用于在不同的应用程序之间实现数据共享的功能。它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。
内容提供器可以选择只对哪一部分数据进行共享,从而保证我们程序中的隐私数据不会有泄漏的风险。
7.2 运行权限
Android 6.0引用了运行时权限功能,很好地保护了用户的安全和隐私。
7.2.1 Android权限机制详解
Android要求我们在访问用户涉及到安全性的时候,需要在AndroidManifest.xml中加入相应的权限。这样用户就在如下两个方面得到了保护
在低于6.0的系统设备上安装程序时,就会在安装界面提醒用户该apk需要的权限
用户可以在应用程序管理界面查看任意一个程序的权限申请情况
但很多常用的软件存在“店大欺客”的情况,滥用很多权限。因此Android研发团队在6.0时就加入了运行时权限功能。即用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权。
当然并不是所有的权限都是在运行时申请。
● 普通权限
● 危险权限
普通权限:是指那些不会威胁到用户的安全和隐私的权限,系统会自动帮我们进行授权。
危险权限:是指那些可能会触及用户隐私或者对设备安全性造成影响的权限,必须要由用户手动点击授权才行,否则程序就无法使用相应的功能。
Android中的危险权限主要有如下几种:
注意:表中每一个权限都属于一个权限组,在处理运行时权限时使用权限名,如果用户一旦同意授权了,那么该权限所对应的权限组中所有的其他权限也会同时被授权。
7.2.2 在程序运行时申请权限
android 申请权限API:
1.checkSelfPermission 检查权限是否允许
2 requestPermissions 请求某个或某几个权限
3.onRequestPermissionsResult 手动请求权限之后的结果回调
4.shouldShowRequestPermissionRationale “不在询问”
特别注意 shouldShowRequestPermissionRationale :
1.第一次用户没有请求权限 false
2.用户第一次请求了权限 拒绝true 允许 false
3.用户再次请求 显示不在询问 点击不在询问 拒绝 false 点击不在询问允许false
只有当用户选择不在提醒拒绝是返回false
解释说明:
第一步:判断用户是不是已经给我们授权过
用checkSelfPermission()方法去判断用户是否授过权。共接收两个参数:
参数一:上下文
参数二:具体的权限名 Manifest.permission.xxxxx
第二步:将返回值与PackageManager.PERMISSION_GRANTED做比较,如果相等就说明用户已经授权,如果不相等就表示用户没有授权。
第三步:如果没有授权,则调用requestPermissions()方法向用户申请授权。requestPermissions()共接收三个参数:
参数一:Activity实例
参数二:String数组,把要申请的权限名放在数组中
参数三:请求码,只要确保是唯一值就行
**第四步:**对授权的结果进行判断
判断用户有没有 “点击不在询问” ,点击了主动跳转到设置画面,手动开放权限,
注意:当用户第一次启动apk,进行权限请求是“不在询问” 不显示,只有在以后的权限请求是才显示,当用户点击 “不在询问” 则返回false
例如:
点击button 权限请求
public class MainActivity extends AppCompatActivity {
private static final String TAG = "permission";
private String[] perm = {
Manifest.permission.ACCESS_COARSE_LOCATION, //定位权限
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_PHONE_STATE
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG,"onCreate");
}
public void Call(View view) {
switch (view.getId()) {
case R.id.button:
CheckPermission(perm);
break;
case R.id.button1:
break;
}
}
public void CheckPermission(String [] perm) {
//1.首先检查有没有权限
//2.在请求权限
//3.
if (Build.VERSION.SDK_INT>23 && this.getApplicationInfo().targetSdkVersion>23) {
List<String> denpermis = new ArrayList<>();
for (String string:perm) {
int result = this.checkSelfPermission(string);
if (result!= PackageManager.PERMISSION_GRANTED) {
denpermis.add(string);
}
}
if (denpermis.size()!=0) {
String[] strings = denpermis.toArray(new String[denpermis.size()]);
this.requestPermissions(strings,0);
}
}
}
//权限结果
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Log.d(TAG,"onRequestPermissionsResult:"+requestCode+" "+permissions.length+" "+ Arrays.toString(grantResults));
for (int i=0;i<grantResults.length;i++) {
if (grantResults[i]!=PackageManager.PERMISSION_GRANTED) {//没有点击允许
boolean is = this.shouldShowRequestPermissionRationale(permissions[i]); //第一次进入是默认是false 以后都是true
if (is) {
Log.d(TAG,"true");
}else {
//点击了不在询问 手动 跳转到设置界面
Log.d(TAG,"false");
showMissingPermissionDialog();
break;
}
}
}
}
private void showMissingPermissionDialog() {//如果权限没有获取,弹窗显示
try{
Log.d(TAG, "showMissingPermissionDialog ");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("当前应用缺少必要权限。\\n\\n请点击\\\"设置\\\"-\\\"权限\\\"-打开所需权限");
// 拒绝, 退出应用
builder.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try{
finish();
} catch (Throwable e) {
e.printStackTrace();
}
}
});
//进入设置,设置权限
builder.setPositiveButton("设置",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
startAppSettings();//启动设置
} catch (Throwable e) {
e.printStackTrace();
}
}
});
builder.setCancelable(false);
builder.show();
}catch(Throwable e){
e.printStackTrace();
}
}
private void startAppSettings() {
try{
Log.d(TAG, "startAppSettings begin ");
Intent intent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
Log.d(TAG, "startActivity end");
} catch (Throwable e) {
e.printStackTrace();
}
}
}
7.3 访问其他程序中的数据
内容提供器的用法主要有两种:
- 使用现有的内容提供器来读取和操作相应程序中的数据
- 创建自己的内容提供器给我们程序的数据提供外部访问接口
如果一个应用程序通过内容提供器对其数据提供了外部访问接口,那么任何其他的应用程序就都可以对这部分数据进行访问,Android系统中自带的电话薄,短信,媒体库,等程序都提供了类似的接口,这就使得第三方应用程序可以充分的利用这部分数据来实现更好的功能。