好久没更新文章了,近期在做通讯录上传,把它分享出来,送给需要的朋友。

写了一个通讯录工具类,直接放代码吧,关键位置通过注释来解释。

这个工具类包含通讯录获取,加密,然后上传操作。看不懂的可以留言

import android.database.Cursor;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.util.Base64; import com.demo.alfar.app.AlfarApplication;
import com.demo.alfar.data.ActionDataManager;
import com.demo.alfar.data.common.BaseThrowable;
import com.demo.alfar.data.model.ConfigurationInfo;
import com.demo.alfar.data.model.EmptyData;
import com.demo.alfar.service.action.DeviceActionMvpView;
import com.demo.alfar.service.action.DeviceActionPresenter;
import com.demo.common.utils.LogUtil;
import com.demo.common.utils.SpFileUtil;
import com.demo.common.utils.StringUtils; import java.io.UnsupportedEncodingException;
import java.util.List; public class ContactReader { //通过下面字符进行分割,组成字符串
static String fieldSplit = "\u0001";
static String lineSplit = "\u0002"; static String newStr; public static class ContactReaderReporter extends AsyncTask<String, Void, Integer> {
@Override
protected Integer doInBackground(String... argus) {
String contactInfo = ""; Cursor cursor = null;
try {
cursor = AlfarApplication.getApplication().getContentResolver()
.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
int contactIdIndex = 0;
int nameIndex = 0; if (cursor.getCount() > 0) {
contactIdIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);
nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
}
while (cursor.moveToNext()) {
String element = "";
String contactId = cursor.getString(contactIdIndex);
String name = cursor.getString(nameIndex);
element = name + fieldSplit;
Cursor phones = null;
try {
/*
* 查找该联系人的phone信息
*/
phones = AlfarApplication.getApplication().getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null);
int phoneIndex = 0;
if (phones.getCount() > 0) {
phoneIndex = phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
}
while (phones.moveToNext()) {
String phoneNumber = phones.getString(phoneIndex);
element += phoneNumber + lineSplit;
}
} catch (Exception e) {
} finally {
if (phones != null) {
phones.close();
}
}
Cursor emails = null;
try {
/*
* 查找该联系人的email信息
*/
emails = AlfarApplication.getApplication().getContentResolver()
.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Email.CONTACT_ID + "=" + contactId, null, null);
int emailIndex = 0;
if (emails.getCount() > 0) {
emailIndex = emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA);
}
while (emails.moveToNext()) {
String email = emails.getString(emailIndex);
element += email + fieldSplit;
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if (emails != null) {
emails.close();
}
}
element += lineSplit;
contactInfo += element; }
if (StringUtils.isNotEmpty(contactInfo)) {
LogUtil.Y("prePhoneNum:" + contactInfo);
newStr = encodeStr(contactInfo);
LogUtil.Y("finalPhoneNum:" + newStr);
//这个是mvp模块中的网络请求部分,可忽略一下逻辑,也可进行替换
DeviceActionPresenter actionDataManager = new DeviceActionPresenter(new ActionDataManager());
actionDataManager.attachView(new DeviceActionMvpView() {
@Override
public void onDeviceActionSuccess(EmptyData response) {
SpFileUtil.saveBoolean(AlfarApplication.getApplication(), SpFileUtil.FILE_PARAMS_DATA, SpFileUtil.KEY_POST_CONTENT_SUCCEED, true);
} @Override
public void onDeviceActionFail(BaseThrowable response) {
SpFileUtil.saveBoolean(AlfarApplication.getApplication(), SpFileUtil.FILE_PARAMS_DATA, SpFileUtil.KEY_POST_CONTENT_SUCCEED, false);
} @Override
public void onGetConfigurationsSuccess(List<ConfigurationInfo> response) { } @Override
public void showLoading() { } @Override
public void hideLoading() { }
});
actionDataManager.postClientContent(newStr);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (cursor != null) {
cursor.close();
cursor = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null; } } /**
* 执行上传操作
*/
static public void onContactURLReport() {
Boolean isSuccess = SpFileUtil.getBoolean(AlfarApplication.getApplication(), SpFileUtil.FILE_PARAMS_DATA, SpFileUtil.KEY_POST_CONTENT_SUCCEED, false);
if (!isSuccess) {
try {
ContactReaderReporter task = new ContactReaderReporter();
task.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* 加密字符串,这是一个简单的算法,先base64加密之后,进行字符反转,服务端解密时候同样先进行字符反转,换成=号即可,然后再decode即可
*
* @param info
* @return
*/
public static String encodeStr(String info) { String baseStr = null;
try {
baseStr = Base64.encodeToString(info.getBytes("UTF-8"), Base64.NO_PADDING | Base64.NO_WRAP);
} catch (Exception e) {
e.printStackTrace();
}
String newStr = "";
int half = baseStr.length() / 2;
for (int i = 0; i < half; ++i) {
if (i % 2 != 0) {
newStr = newStr + (char) (baseStr.codePointAt(baseStr.length() - 1 - i));
} else {
newStr = newStr + (char) (baseStr.codePointAt(i));
}
}
if (baseStr.length() % 2 == 1) {
newStr = newStr + (char) (baseStr.codePointAt(baseStr.length() / 2));
}
for (int i = half - 1; i >= 0; --i) {
if (i % 2 != 0) {
newStr = newStr + (char) (baseStr.codePointAt(i));
} else {
newStr = newStr + (char) (baseStr.codePointAt(baseStr.length() - 1 - i));
}
}
return newStr; }
}

  使用方法就是:

ContactReader.onContactURLReport();//上报通讯录信息即可
上面解密后的数据日志为(声明:通讯录数据都是假数据,如有雷同,纯属巧合,可联系我删除):

原数据是上面这样,中间是有点的,下面这个被编辑器去掉了


12-21 18:42:51.018 com.demo.alfar I/===y: prePhoneNum:马云18516886666骚扰电话15321114592广告推销17343150842李彦宏电话15301102735咋骗电话18101055214马化腾18666666666李科云18555555555
12-21 18:42:51.019 com.demo.alfar I/===y: finalPhoneNum:6gm15Tq1ATE1NTE4OTgRNLYRA6LOqprCigD2ljX2rj02MDUxMgEFMuQMOOIpAuWCvTWyiTawqDmxgTEBN5MoMLEnMpgpMoIl5g215z2y5T6x5zS16T+dAKE1M5APMaAmNbMOApLCkgv0qDf1lzX0rz0xMAgUMOEONuURM+Q5AumCrTW1lTixvjEzOTYBN5YoNLYnNbIm5p2p5ge25jq2ADE2NTU4NTURNLUsAaI

 获取通讯录需要权限,记着提前申请:

Manifest.permission.READ_CONTACTS

  

----------附上base64位加密后面附带的参数解释----

CRLF 这个参数看起来比较眼熟,它就是Win风格的换行符,意思就是使用CR LF这一对作为一行的结尾而不是Unix风格的LF

DEFAULT 这个参数是默认,使用默认的方法来加密

NO_PADDING 这个参数是略去加密字符串最后的”=”

NO_WRAP 这个参数意思是略去所有的换行符(设置后CRLF就没用了)

URL_SAFE 这个参数意思是加密时不使用对URL和文件名有特殊意义的字符来作为加密字符,具体就是以-和_取代+和/

----------------------------------------------

Android获取通讯录并上传(包含通讯录加密)的更多相关文章

  1. 简单的 Android 拍照并显示以及获取路径后上传

    简单的 Android 拍照并显示以及获取路径后上传 Activity 中的代码,我只贴出重要的事件部分代码 public void doPhoto(View view) { destoryBimap ...

  2. Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

  3. android+nutz后台如何上传和下载图片

    android+nutz后台如何上传和下载图片  发布于 588天前  作者 yummy222  428 次浏览  复制  上一个帖子  下一个帖子  标签: 无 最近在做一个基于android的ap ...

  4. Android连接socket服务器上传下载多个文件

    android连接socket服务器上传下载多个文件1.socket服务端SocketServer.java public class SocketServer { ;// 端口号,必须与客户端一致 ...

  5. Android+Spring Boot 选择+上传+下载文件

    2021.02.03更新 1 概述 前端Android,上传与下载文件,使用OkHttp处理请求,后端使用Spring Boot,处理Android发送来的上传与下载请求.这个其实不难,就是特别多奇奇 ...

  6. Android端通过HttpURLConnection上传文件到服务器

    Android端通过HttpURLConnection上传文件到服务器 一:实现原理 最近在做Android客户端的应用开发,涉及到要把图片上传到后台服务器中,自己选择了做Spring3 MVC HT ...

  7. Springboot框架中request.getInputStream()获取不到上传的文件流

    Springboot框架中用下面的代码,使用request.getInputStream()获取不到上传的文件流 @PostMapping("/upload_img") publi ...

  8. Android端通过HttpURLConnection上传文件到server

    Android端通过HttpURLConnection上传文件到server 一:实现原理 近期在做Androidclient的应用开发,涉及到要把图片上传到后台server中.自己选择了做Sprin ...

  9. Android实现TCP断点上传,后台C#服务实现接收

    终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证, ...

随机推荐

  1. bind注意事项(传引用参数的时候)

    默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中. 当需要把对象传到bind中的参数中时,需要使用ref或者cref. 例如: #include<iostream&g ...

  2. instance of的java用法

    http://blog.csdn.net/liranke/article/details/5574791

  3. mysql group_concat时间用法

    第一张表的worksId在第二张表中对应多条数据,需要将每条数据的日期作为结果查询出来,一个作为“初审时间”,另一个作为“复审时间”: 可以使用group_concat 和 group by 来进行分 ...

  4. 爬虫3 requests基础

    import requests # get实例 # res = requests.get('http://httpbin.org/get') # # res.encoding='utf-8' # pr ...

  5. Jmeter压测过程报错the target server failed to respond

    失败事务报错信息如下, Socket closed Non HTTP response code: org.apache.http.NoHttpResponseException (the targe ...

  6. CC NOV17

    PERPALIN 可以考虑最后的状态可以是两个非常长而且相同的前缀和后缀中间再加一小段,然后就是不断缩小区间至出解 CHEFHPAL 发现当字符集大于等于3的时候abc循环一定是没有大于1的回文子串的 ...

  7. java项目中Excel文件的导入导出

    package poi.excel; import java.io.IOException; import java.io.InputStream; import java.io.OutputStre ...

  8. Django session 源码流程

    流程 Django session源码流程 首先执行的是SessionMiddleware的init方法 import_module(settings.SESSION_ENGINE) 导入了一个 dj ...

  9. Django content-type 使用

    1.models class PricePolicy(models.Model): """价格与有课程效期表""" content_type ...

  10. Markdown 的离线编辑工具推荐:Sublime Text3 or Typora?我推荐Typora

    最新版Sublime Text3 通过插件的方式,可以完美支持Markdown文档的编写,但是,唯一不完美的是实时预览的缺陷.可能各位看官要喷了,谁说Sublime Text3 不能实时预览的?你看: ...