原文:Android之运行时相机权限和联系人权限获取

本文链接:http://blog.csdn.net/qq_16628781/article/details/61623502

Android之运行时相机权限和联系人权限获取(最后又源码可以下载下来看)

知识点:

1、Android M 及以上系统的动态权限申请;

2、知识名词记录

{

CameraPreview:自定义相机预览类

ViewAnimator:配合framelayout使用,在两个view之间切换时,会有切换动画

ContactsContract:

CursorLoader:

ContentProviderOperation:插入联系人用

读取联系人列表;

}(这里我决定,每篇文章中遇到的“新名词”我都会记录在这里,作为自己下一步需要了解的知识;大家有兴趣的话,也可以循着这些新的专业名词,一步一步的走向Android更深的“泥潭”)

如果你有持续关注Android官方最新的SDK版本的话,你就会知道,Android官方对权限的管理变得原来越严格了。在5.0之后,权限不再是全部都在manifest文件里头申请就OK了,你APP要的权限,当用到的时候,系统才会赋予给你。

当然,你可以这样做,但是要把你的targetSdkVersion 变为22以下,这样是可以暂时避免动态申请权限引起的“麻烦事”,但是这是一个不可逆的趋势,我们必须要顺从它,而不是抗拒它,况且紧靠几个人几个应用,那是螳臂当车。

权限分为:普通权限,危险权限和系统权限;

普通权限:这些权限对于用户隐私和设备操作不会造成太多危险,主要有:

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

危险权限,主要是包含产生费用或者是读取用户隐私的权限,包含:

group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR group:android.permission-group.CAMERA
permission:android.permission.CAMERA group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS

上图:

下面我这里利用请求相机和联系人权限来演示一下在Android M 系统上的权限请求;我在这里做了两个fragment页面,分别是相机和联系人相关的动作。

这里我就只是贴一个主要的页面代码就好了,我这里只是要一个触发相机和联系人的动作就好了,代码里头都有说明。

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ViewAnimator; import com.example.android.common.logger.Log;
import com.example.android.common.logger.LogFragment;
import com.example.android.common.logger.LogWrapper;
import com.example.android.common.logger.MessageOnlyLogFilter;
import com.example.android.system.runtimepermissions.camera.CameraPreviewFragment;
import com.example.android.system.runtimepermissions.contacts.ContactsFragment; import common.activities.SampleActivityBase; public class MainActivity extends SampleActivityBase
implements ActivityCompat.OnRequestPermissionsResultCallback { public static final String TAG = "MainActivity"; /* 相机请求码 */
private static final int REQUEST_CAMERA = 0; /* 联系人请求码 */
private static final int REQUEST_CONTACTS = 1; /* 请求读取联系人权限 */
private static String[] PERMISSIONS_CONTACT = {Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS}; // 标志log fragment是否显示
private boolean mLogShown; /* 主页的布局,依靠动态加载进来 */
private View mLayout; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLayout = findViewById(R.id.sample_main_layout); if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
RuntimePermissionsFragment fragment = new RuntimePermissionsFragment();
transaction.replace(R.id.sample_content_fragment, fragment);
transaction.commit();
}
initializeLogging();
} /**
* 点击显示联系人按钮相应
* <p>
* 回调已经被定义好了
*/
public void showCamera(View view) {
Log.i(TAG, "检查权限是否被受理!");
// 检查是否想要的权限申请是否弹框。如果是第一次申请,用户不通过,
// 那么第二次申请的话,就要给用户说明为什么需要申请这个权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// 权限未被授予
requestCameraPermission();
} else {
Log.i(TAG, "相机权限已经被受理,开始预览相机!");
showCameraPreview();
}
} /**
* 申请相机权限
*/
private void requestCameraPermission() {
Log.i(TAG, "相机权限未被授予,需要申请!");
// 相机权限未被授予,需要申请!
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CAMERA)) {
// 如果访问了,但是没有被授予权限,则需要告诉用户,使用此权限的好处
Log.i(TAG, "申请权限说明!");
Snackbar.make(mLayout, R.string.permission_camera_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
// 这里重新申请权限
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA);
}
})
.show();
} else {
// 第一次申请,就直接申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA);
}
} public void showContacts(View v) {
// 判断权限是否拥有
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED
|| ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "读写联系人权限未被授予,需要申请!");
// 读写联系人权限未被授予,需要申请!
requestContactsPermissions();
} else {
// 权限已经被授予,显示细节页面!
Log.i(TAG, "权限已经被授予,显示细节页面!");
showContactDetails();
}
} /**
* 申请联系人读取权限
*/
private void requestContactsPermissions() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.READ_CONTACTS)
|| ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.WRITE_CONTACTS)) {
// 如果是第二次申请,需要向用户说明为何使用此权限,会带出一个不再询问的复选框!
Log.i(TAG, "如果是第二次申请,需要向用户说明为何使用此权限,会带出一个不再询问的复选框!"); Snackbar.make(mLayout, R.string.permission_contacts_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
@Override
public void onClick(View view) {
ActivityCompat
.requestPermissions(MainActivity.this, PERMISSIONS_CONTACT,
REQUEST_CONTACTS);
}
})
.show();
} else {
// 第一次申请此权限,直接申请
ActivityCompat.requestPermissions(this, PERMISSIONS_CONTACT, REQUEST_CONTACTS);
}
} /**
* 显示相机预览界面
*/
private void showCameraPreview() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
.addToBackStack("contacts")
.commit();
} /**
* 显示联系人页面
*/
private void showContactDetails() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, ContactsFragment.newInstance())
.addToBackStack("contacts")
.commit();
} /**
* 申请权限的回调,
*
* @param requestCode requestCode
* @param permissions permissions
* @param grantResults grantResults 多个权限一起返回
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Snackbar.make(mLayout, R.string.permision_available_camera,
Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(mLayout, R.string.permissions_not_granted,
Snackbar.LENGTH_SHORT).show();
}
} else if (requestCode == REQUEST_CONTACTS) {
// 这里有个多权限的检查,需要检查每一个权限是否都被授权了
if (PermissionUtil.verifyPermissions(grantResults)) {
// true,所有权限已经被授予
Snackbar.make(mLayout, R.string.permision_available_contacts,
Snackbar.LENGTH_SHORT)
.show();
} else {
// false,并不是所有权限都被授予
Snackbar.make(mLayout, R.string.permissions_not_granted, Snackbar.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
} @Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
return super.onPrepareOptionsMenu(menu);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_toggle_log:
mLogShown = !mLogShown;
ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
if (mLogShown) {
output.setDisplayedChild(1);
} else {
output.setDisplayedChild(0);
}
supportInvalidateOptionsMenu();
return true;
}
return super.onOptionsItemSelected(item);
} /**
* 初始化log日志
*/
@Override
public void initializeLogging() {
LogWrapper logWrapper = new LogWrapper();
Log.setLogNode(logWrapper); MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
logWrapper.setNext(msgFilter); LogFragment logFragment = (LogFragment) getSupportFragmentManager()
.findFragmentById(R.id.log_fragment);
msgFilter.setNext(logFragment.getLogView());
} public void onBackClick(View view) {
// 因为我们对fragment入栈处理,按返回键的时候,出栈处理
getSupportFragmentManager().popBackStack();
} }

第一,我们申请权限的方法:

ActivityCompat.requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode){}

第二,是申请的结果回调方法:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults){}

以上就是主要的两个方法了。

当然,还要注意一下,是否是第一次申请权限?需不需要想用户说明我这个权限是用来干嘛的?如果用户不授权,我的APP该如何来操作防止崩溃?用户随时可以取消对你APP的授权,那时我们又该如何来做?

问题好多好多,我们要走的路还很长。但是我这里有几个方法,适合大家去咀嚼咀嚼。

第一个:

ActivityCompat.shouldShowRequestPermissionRationale(this,

                Manifest.permission.READ_CONTACTS)

这个方法呢,说的是,当你第一次去请求权限的时候,如果用户拒绝了,然后第二次再去申请此权限,那么这个方法会返回一个true的结果,告诉你,上一次用户不同意给你这个权限,然后这次你就需要向用户说明为什么你需要这个权限。

我们看到的效果图,是有相机预览和查看联系人的页面的,这里我就不一一把代码贴出来,我会在最后面把工程代码放到GitHub上面,给大家下载。里面有更加详细的说明。

代码下载:点击打开链接

如有任何问题,请及时与我联系,谢谢!

Android之运行时相机权限和联系人权限获取的更多相关文章

  1. Android ART运行时无缝替换Dalvik虚拟机的过程分析

    Android ART运行时无缝替换Dalvik虚拟机的过程分析 分类: Android2014-01-13 00:59 42722人阅读 评论(66) 收藏 举报 AndroidARTDalvikV ...

  2. Android 请求运行时权限

    写文件到sd卡中,会报权限问题,需要动态申请申请运行时权限 1. MainActivity.java public class MainActivity extends Activity { priv ...

  3. Android程序运行时权限与文件系统权限的区别

    apk程序是运行在虚拟机上的,对应的是Android独特的权限机制,只有体现到文件系统上时才使用linux的权限设置. (1)Android中的apk必须签名 (2)基于UserID的进程级别的安全机 ...

  4. 如何解决android studio 运行时中文乱码的问题

    相信很多朋友都会遇到android studio 在MAC OS中运行的时候中文乱码.而在代码编辑的时候正常.经过几天的不断寻找解决办法,终于解决了 比如: Toast.makeText(MainAc ...

  5. Android 中运行时权限获取联系人信息 Demo

    代码比较简单... AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <m ...

  6. Android 7.0 之后相机/文件读写等权限获取方式改变,导致开启相机闪退

    在 Android 7.0 之前 Google 提供的动态申请权限的 API,可以调用相机拍照,访问SDcard等操作都只需要申请对应的权限,如下: <uses-permission andro ...

  7. Android webview 运行时不调用系统自带浏览器

    WebView mobView = new WebView(this); mobView.loadUrl("http://www.csdn.net"); WebSettings w ...

  8. [置顶] 完美解决Android Studio 运行时出现的警告信息?

    今天群友看到他说运行的时候报下面的错,我记得我之前导入百度地图也是遇到过,运行的时候一堆警告信息,然后编译失败等的,特别郁闷,其实后来在网上查了下,原来是很多第三方里面加个混淆,然后你有找不到那些方法 ...

  9. Appium运行时没有启动activity的权限:A new session could not be created.(Original error: Permission to start activity denied)

    小白搞appium,遇到启动不了activity的问题: 查找解决方案说是跟AndroidManifest.xml有关系,参考:https://github.com/appium/appium/iss ...

随机推荐

  1. java 多线程(三)条件对象

    转载请注明出处:http://blog.csdn.net/xingjiarong/article/details/47417383 在上一篇博客中,我们学会了用ReentrantLock来控制线程訪问 ...

  2. Quartz.NET 3.0.7 + MySql 实现动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(一)

    原文:Quartz.NET 3.0.7 + MySql 实现动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(一) 前端时间,接到领导任务,写了一个调度框架.今天决定把心路历程记 ...

  3. jquery pagination分页的两种实现方式

    原文链接:http://blog.csdn.net/qq_37936542/article/details/79457012 此插件是jQuery的ajax分页插件.如果你用到此插件作分页的时候,涉及 ...

  4. [NPM] List available npm scripts and support tab completion

    In this lesson we will look at different ways you can list the available npm scripts. Whether we wan ...

  5. Oracle导入脚本文件乱码问题

    用脚本直接导入,Oracle出现乱码 绝大多数情况是Oracle客户端环境变量NLS_LANG的值和数据库字符集不一致导致. (注nls_lang修改的是Oracle客户端字符集的编码,locale命 ...

  6. 电子商务系统的设计与实现(十三):分页组件,从前到后,从JS到Java

    一.概述   学习实践Web开发5年多了,直到今天,我才算真正实现了最基本最常用的分页组件. 包括:    a.前端JS异步加载并渲染:    b.前端JSP.Freemarker.Struts标签渲 ...

  7. 安装CentOS6.2操作系统

    原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...

  8. 原生H5页面模拟APP左侧滑动删除效果

    话不多说,往左侧滑动,显示删除,我们先来看一下效果图:如下: 这个布局我就不多说,反正就是一行ul,li, class名“item” js代码如下: $(".item").on(& ...

  9. nodebb中文社区

    V2MM —— 自由职业者社区 https://v2mm.tech/ 萌梦社区 https://qtdream.com/ React Native 中文社区 http://bbs.reactnativ ...

  10. apt-get install 的参数(add-apt-repository)

    apt-get install 是 ubuntu 下的软件安装命令. sudo apt-get -y install: -y:yes,在命令行交互提示中,直接输入 yes: 1. 使用 add-apt ...