五、ContentProvider权限动态申请 通讯录增删改查

五、ContentProvider相关

ContentProvider内容提供者: 负责数据存取,常用于APP进数据共享,跨进程数据存取等…比如读取相册,读取联系人,都是ContentProvider来实现的

  • **1.**我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信、相册等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了!
  • **2.**我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露!

五、ContentProvider权限动态申请 通讯录增删改查

1.权限申请

从android6.0开始,凡是涉及用户隐私的权限(读写短信,读写联系人,拍摄,录音等等),都需要运行时申请,弹窗提醒用户是否授权。用户不授权则无法继续操作

首先在AndroidManifest.xml中声明读取通信录的权限

<uses-permission android:name="android.permission.READ_CONTACTS"/>

运行时动态申请权限,请求用户授权

class TestContentProviderActivity : AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //判断读取通讯录的允许
        if(ActivityCompat.checkSelfPermission(this , android.Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
            //如果未授权
            ActivityCompat.requestPermissions(
                this ,
                arrayOf(android.Manifest.permission.READ_CONTACTS) ,
                100)
        }else{
            getContacts() //读取联系人
        }
    }

    //读取联系人
    private fun getContacts() {
        Toast.makeText(this, "getContacts", Toast.LENGTH_SHORT).show()
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if(requestCode==100 && permissions[0]==android.Manifest.permission.READ_CONTACTS){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ //表示授予权限
                getContacts()
            }else{
                Toast.makeText(this,"读取通讯录的权限被拒绝,程序将无法继续工作",Toast.LENGTH_LONG).show()
            }
        }
    }
}

2.读取通讯录联系人

表名 说明
content://com.android.contacts/data/phones 读取联系人的表的名字
字段 说明
display_name 用户名
Data1 手机号
//读取联系人
@SuppressLint("Range")
private fun getContacts() {
    //查询对象
    val resolver = contentResolver
    //格式化一个uri
    val uri = Uri.parse("content://com.android.contacts/data/phones")
    //得到一个游标
    val cursor = resolver.query(uri, null, null, null, null)?:return

    while (cursor.moveToNext()) {
        //获取联系人名字和号码
        val displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
        val phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
        Log.e("ContentProvider", "姓名:$displayName")
        Log.e("ContentProvider", "号码:$phoneNumber")
        Log.e("ContentProvider", "======================")
    }
    cursor.close() //游标关闭!!
}

3.通信录插入联系人

表名 说明
content://com.android.contacts/data/data 插入联系人的表的名字
content://com.android.contacts/data/raw_contacts 插入联系人的原始表的名字
//插入联系人
private fun insertContact() {
    /*
     * 首先向RawContacts.CONTENT_URI执行一个空值插入,目的是获得系统返回的rawContactId
     * 这时后面插入data表的数据,才能使插入的联系人在通讯录里面可见
     */
    val resolver = contentResolver
    val values = ContentValues()
    val rawContactUri = contentResolver!!.insert(ContactsContract.RawContacts.CONTENT_URI, values)!!
    val rawContactId = ContentUris.parseId(rawContactUri)

    //往data表里写入姓名数据
    values.clear() //先把可能存在的数据清空
    values.put(ContactsContract.Data.RAW_CONTACT_ID , rawContactId)
    values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) //内容类型
    values.put(CommonDataKinds.StructuredName.GIVEN_NAME , "some_name")
    resolver.insert(ContactsContract.Data.CONTENT_URI , values)

    //往data表里写入电话数据
    values.clear() //先把可能存在的数据清空
    values.put(ContactsContract.Data.RAW_CONTACT_ID , rawContactId)
    values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.Phone.CONTENT_ITEM_TYPE) //内容类型
    values.put(CommonDataKinds.Phone.NUMBER , "1231231234")
    values.put(CommonDataKinds.Phone.TYPE , CommonDataKinds.Phone.TYPE_MOBILE) //手机号
    resolver.insert(ContactsContract.Data.CONTENT_URI , values)

    //往data表里写入Email的数据
    values.clear() //先把可能存在的数据清空
    values.put(ContactsContract.Data.RAW_CONTACT_ID , rawContactId)
    values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.Email.CONTENT_ITEM_TYPE) //内容类型
    values.put(CommonDataKinds.Email.DATA , "some_name@xx.com")
    values.put(CommonDataKinds.Email.TYPE , CommonDataKinds.Email.TYPE_HOME) //家庭邮箱
    resolver.insert(ContactsContract.Data.CONTENT_URI , values)
}

4.更新联系人信息

  • 根据手机号获取联系人在通讯录的contact_id
@SuppressLint("Range")
fun getContactIdByPhone(phone : Long) : String?{
    val uri = Uri.parse("content://com.android.contacts/data/phones/filter/$phone")
    val resolver = contentResolver
    val cursor = resolver.query(uri, arrayOf(ContactsContract.Data.CONTACT_ID), null, null, null)?:return null

    if (cursor.moveToNext()){
        val contractId = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
        return contractId
    }

    return null
}
  • 更新联系人的姓名
//更新联系人
private fun updateContact() {
    val contractId = getContactIdByPhone(234524)
    if(contractId == null){
        Toast.makeText(this , "联系人不存在,无法更新" , Toast.LENGTH_LONG).show()
        return
    }

    val values = ContentValues()
    values.put(ContactsContract.Data.MIMETYPE , CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
    values.put(CommonDataKinds.StructuredName.GIVEN_NAME, "new_name")
    contentResolver.update(
        ContactsContract.Data.CONTENT_URI,
        values,
        "${ContactsContract.Data.CONTACT_ID}=?",
        arrayOf(contractId)
    )

}

5.删除联系人

  • 根据姓名删除联系人
val ret = contentResolver.delete(
    ContactsContract.RawContacts.CONTENT_URI,
    CommonDataKinds.Phone.DISPLAY_NAME + "=?",
    arrayOf("some_name")
)
if(ret>0){
    Toast.makeText(this,"删除成功", Toast.LENGTH_SHORT).show()
}else{
    Toast.makeText(this, "删除失败", Toast.LENGTH_SHORT).show()
}
  • 根据手机号删除联系人
val contact_id = getContactIdByPhone(1111)

contentResolver.delete(RawContacts.CONTENT_URI,CommonDataKinds.Phone.CONTACT_ID+"=?", arrayOf(contact_id));

6.读取收件箱所有短信

字段 说明
address 收件人地址,即手机号,如+8613811810000
person 人物
date 日期,long型,如1256539465022,可以对日期显示格式进行设置
protocol 协议0 :SMS_RPOTO短信,1:MMS_PROTO彩信
read 是否阅读0:未读,1:已读
type 短信类型1: 接收到的短信,2:发出的短信
body 短信具体内容

需要动态获取权限

<uses-permission android:name="android.permission.READ_SMS"/>
private fun getMessage() {
    val uri = Uri.parse("content://sms/")
    val resolver = contentResolver
    //查询短信的  发件人地址  日期     短信类型  短信具体内容
    val cursor = resolver.query(uri, arrayOf("address", "address", "type", "body"), null, null, null)?:return
    while (cursor.moveToNext()){
        val address = cursor.getString(0)
        val data = cursor.getString(1)
        val type = cursor.getString(2)
        val body = cursor.getString(3)

        Log.e("ContentProvider","收件人 $address")
        Log.e("ContentProvider","类型时间 [$type]:$data")
        Log.e("ContentProvider","短信内容 $body")
        Log.e("ContentProvider","-----------------------------")
    }

    cursor.close() //关闭游标!!
}

短信相关的其它操作uri

content://sms/ 所有短信

content://sms/inbox 收件箱

content://sms/sent 已发送

content://sms/draft 草稿

content://sms/outbox 发件箱

content://sms/failed 发送失败

content://sms/queued 待发送列表

上一篇:Arcpy学习笔记(二)之Arcpy函数-游标Cursor


下一篇:全国计算机等级考试c语言程序设计二级考试题库