本文连接:http://blog.csdn.net/qq_16628781/article/details/61623502css
Android之运行时相机权限和联系人权限获取(最后又源码能够下载下来看)html
知识点:java
一、Android M 及以上系统的动态权限申请;android
二、知识名词记录git
{github
CameraPreview:自定义相机预览类app
ViewAnimator:配合framelayout使用,在两个view之间切换时,会有切换动画ide
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
上图:
这里我就只是贴一个主要的页面代码就行了,我这里只是要一个触发相机和联系人的动做就行了,代码里头都有说明。
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上面,给你们下载。里面有更加详细的说明。
代码下载:点击打开连接
若有任何问题,请及时与我联系,谢谢!