val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")if (cursor != null) { while (cursor.moveToNext()) { val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID)) val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id) println("image uri is $uri") } cursor.close()}
SAF(存储访问框架--Storage Access Framework)
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)intent.addCategory(Intent.CATEGORY_OPENABLE)intent.type = "image/*"startActivityForResult(intent, 100)@RequiresApi(Build.VERSION_CODES.KITKAT)override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (data == null || resultCode != Activity.RESULT_OK) return if (requestCode == 100) { val uri = data.data println("image uri is $uri") }}说到这里大概又有人问了,那我的应用就是个手机管理器,总不能不让我清其他应用的缓存了吧,有办法!Android提供了两个intent入口:
也就是当用到这两个API的时间,原来的READ_PHONE_STATE权限不管用了,必要READ_PHONE_NUMBERS权限才行。
下面具体说说,targetSdkVersion修改到30,然后运行一个获取电话号码的步伐:
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), 100)btn2.setOnClickListener { val tm = this.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager val phoneNumber = tm.line1Number showToast(phoneNumber)}瓦解了:
java.lang.SecurityException: getLine1NumberForDisplay: Neither user 10151 nor current process has android.permission.READ_PHONE_STATE, android.permission.READ_SMS, or android.permission.READ_PHONE_NUMBERS预想之中哈,Andmanifest.xml中注册好权限,而且添加动态权限申请:
<uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.READ_PHONE_STATE,Manifest.permission.READ_PHONE_NUMBERS), 100)搞定,假如你只必要获取手机号码这一个功能,也可以只申请READ_PHONE_NUMBERS这一个权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="29" /><uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />自界说消息框视图被屏蔽
大概有人会奇怪了,什么是自界说消息框视图啊?我说英文你就知道了,英文是custom toast views,也就是自界说toast。简朴写个代码:
Toast toast = new Toast(context);toast.setDuration(show_length);toast.setView(view);toast.show();糟了糟了,自界说toast被弃用了?我们项目就是用的这个啊!不消担心,只是不允许自界说toast从背景表现了。
好比我写一个3秒后再表现toast,然后应用一打开就进入背景,看看会发生什么:
Handler().postDelayed({ IToast.show("你好,我是自界说toast") }, 3000)W/NotificationService: Blocking custom toast from package com.example.studynote due to package not in the foreground啥也没表现,只是发出来一个告诫。
以是不消太过担心,假如实在必要背景表现,就用平凡的toast吧!
现在必要 APK 署名方案 v2
从Android10体系的装备开始,就必要哀求背景位置权限(ACCESS_BACKGROUND_LOCATION),并选择Allow all the time (始终允许)才华得到背景位置权限。Android11装备上再次增强对背景权限的管理,重要体现在体系对话框上,对话框不再提示始终允许字样,而是提供了位置权限的设置入口,必要在设置页面选择始终允许才华得到背景位置权限。
Android 11 更改了应用查询用户已在装备上安装的其他应用以及与之交互的方式。利用新的 元素,应用可以界说一组自身可访问的其他应用。通过告知体系应向您的应用表现哪些其他应用,此元素有助于鼓励最小权限原则。别的,此元素还可资助 Google Play 等应用市肆评估应用为用户提供的隐私权和安全性。
也就是说,Android11中,假如你想去获取其他应用的信息,好比包名,名称等等,不能直接获取了,必须在清单文件中添加<queries>元素,告知体系你要获取哪些应用信息大概哪一类应用。
好比我这段查询应用信息的代码:
val pm = this.packageManagerval listAppcations: List<ApplicationInfo> = pm .getInstalledApplications(PackageManager.GET_META_DATA)for (app in listAppcations) { Log.e("lz",app.packageName)}在Android11版本,只能查询到自己应用和体系应用的信息,查不到其他应用的信息了。怎么呢?添加<queries>元素,两种方式: