原文: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. [Node.js] Take Screenshots of Multiple Dimensions for Responsive Sites using Nightmare

    When developing responsive websites, you will constantly be resizing your browser to make sure your ...

  2. cat /proc/cpuinfo 引发的思考--CPU 物理封装-物理核心-逻辑核心-超线程之间关系

    CPU的物理封装,一个物理封装使用独立的一个CPU物理插槽,共享电源和风扇: CPU物理核心:在一个物理封装中封装了多个独立CPU核心,每一个CPU核心都有自己独立的完整硬件单元. CPU逻辑核心:一 ...

  3. Android JNI编程(五)——C语言的静态内存分配、动态内存分配、动态创建数组

    版权声明:本文出自阿钟的博客,转载请注明出处:http://blog.csdn.net/a_zhon/. 目录(?)[+] 一:什么是静态内存什么又是动态内存呢? 静态内存:是指在程序开始运行时由编译 ...

  4. 关于IT增值服务"拜师学艺"价格调整的通知

    经过几天的探索,在与若干潜在付费客户交流的基础上,决定对IT增值服务"拜师学艺"价格进行调整. 当前价格:年费1000元,月付100元-1年付10个月. 2015年1月1日起,年费 ...

  5. 原生js如何实现图片翻转旋转效果?

    原生js如何实现图片翻转旋转效果? 一.总结 1.通过给元素设置style中的transition来实现的. 2.我昨天纠结的效果全部可以通过精读这个代码后实现. 二.原生js如何实现图片翻转旋转效果 ...

  6. 断言(Assert)与异常(Exception)

    ## 断言和异常 断言是用来检查非法情况而不是错误情况的,用来帮开发者快速定位问题的位置. 异常处理用于对程序发生异常情况的处理,增强程序的健壮性和容错性. ## 断言的使用 在防御式编程中经常会用断 ...

  7. 移动端iPhone系列适配问题的一些坑

    完成移动端的开发项目之后,发现谷歌自带的调试器似乎没有什么太大的作用,整天借同事的苹果手机测bug,尽管同事不厌其烦,但还是觉得这iPhone系列适配问题适配到想逃逃逃,好在项目已经顺利完成,测试通过 ...

  8. 社会化登录分享-Android SDK的二次封装和使用

    本系列文章将第三方的登录分享功能进行二次封装,统一接口调用,简化了接不同平台登录分享的步骤. 0 系列文章 系列一 Android SDK的二次封装和使用 系列二 源码解析 系列三 微信SDK接入 系 ...

  9. maven Java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet

    如果你可以确认你的maven Dependencies中已经导入了如下的jar包,那么你就要检查下Deployment Assembly 选中项目 alt+enter,然后查看maven依赖有没有被添 ...

  10. win10 uwp 线程池

    原文:win10 uwp 线程池 如果大家有开发 WPF 或以前的程序,大概知道线程池不是 UWP 创造的,实际上在很多技术都用到线程池. 为什么需要线程池,他是什么?如何在 UWP 使用线程池,本文 ...