转载请注明出处:王亟亟的大牛之路
最近在最后的任职期还被榨了一顿忙的飞起,不过今天是最后一天了,帮着处理个BUG就功德圆满了。然后最近在做一个手机间通信+XX监听的Demo,其中一部分是关于短信监听的,然后正好6.0授权的一些因素,那就把这部分的实现单独拆出来做这么个Demo,顺道把这几天觉得发现的不错的第三方库贡献给大家
先来看一下运行效果
先是配置把要过滤的短信字段输入
输入框控件
compile ‘com.github.florent37:materialtextfield:1.0.5‘
然后用一自定义RV来显示/处理输入的内容
compile ‘com.nikhilpanju.recyclerviewenhanced:recyclerviewenhanced:1.0.0‘
然后用户输完就跳转到监听页面,当有短信了,显示如下
再来看下 项目结构
用到的库的清单
dependencies {
compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
testCompile ‘junit:junit:4.12‘
compile ‘com.android.support:appcompat-v7:23.4.0‘
compile ‘com.apkfuns.logutils:library:1.4.2‘
compile ‘com.jakewharton:butterknife:8.1.0‘
compile ‘com.github.navasmdc:MaterialDesign:[email protected]‘
apt ‘com.jakewharton:butterknife-compiler:8.1.0‘
compile ‘com.nikhilpanju.recyclerviewenhanced:recyclerviewenhanced:1.0.0‘
compile ‘com.github.florent37:materialtextfield:1.0.5‘
compile ‘com.lovedise:permissiongen:0.0.6‘
}
OK,来一步步读代码,先从配置开始
public class SettingActivity extends BaseActivity {
@BindView(R.id.input)
EditText input;
@BindView(R.id.add)
ButtonRectangle add;
@BindView(R.id.jump)
ButtonRectangle jump;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
private MainAdapter mAdapter;
private RecyclerTouchListener onTouchListener;
//数据集合
private List<String> list;
@Override
int getLayout() {
return R.layout.activity_setting;
}
@Override
void init() {
ButterKnife.bind(this);
list = new ArrayList<>();
mAdapter = new MainAdapter(this, list);
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
onTouchListener = new RecyclerTouchListener(this, recyclerView);
}
@Override
void logic() {
//注册滑动删除行为
onTouchListener.setSwipeOptionViews(R.id.edit)
.setSwipeable(R.id.rowFG, R.id.rowBG, new RecyclerTouchListener.OnSwipeOptionsClickListener() {
@Override
public void onSwipeOptionClicked(int viewID, int position) {
if (viewID == R.id.edit) {
list.remove(position);
mAdapter.notifyDataSetChanged();
}
}
});
recyclerView.addOnItemTouchListener(onTouchListener);
}
@Override
void onResumeInit() {
//刷新适配器
if (list.size() > 0) {
mAdapter.notifyDataSetChanged();
}
}
@Override
void onResumeLogic() {
}
@Override
protected void onPause() {
super.onPause();
//释放无用资源
recyclerView.removeOnItemTouchListener(onTouchListener);
}
@OnClick({R.id.add, R.id.jump})
public void onClick(View view) {
switch (view.getId()) {
case R.id.add:
String value = input.getText().toString().trim();
if (!value.isEmpty()) {
list.add(value);
mAdapter.notifyDataSetChanged();
input.setText("");
}
break;
case R.id.jump:
if (list.size() > 0) {
Intent intent = new Intent(SettingActivity.this, MainActivity.class);
intent.putStringArrayListExtra("dataList", (ArrayList<String>) list);
startActivity(intent);
} else {
Toast.makeText(getApplicationContext(), "请添加过滤内容", Toast.LENGTH_SHORT).show();
}
break;
}
}
}
具体重要步骤已经在注解里写着了,主要大家可以看下这个RV库,支持部分点击,全局点击和自定义滑动删除在 https://github.com/ddwhan0123/Useful-Open-Source-Android的 RV部分有收纳
再来看下主类
public class MainActivity extends BaseActivity {
private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";
private SMSBroadcastReceiver mSMSBroadcastReceiver;
private List<String> intentList;
@BindView(R.id.text)
TextView text;
@Override
int getLayout() {
return R.layout.activity_main;
}
@Override
void init() {
ButterKnife.bind(this);
//接受传递来的过滤集合
intentList = getIntent().getStringArrayListExtra("dataList");
}
@Override
void logic() {
//授权
PermissionGen.with(MainActivity.this)
.addRequestCode(100)
.permissions(
Manifest.permission.RECEIVE_SMS,
Manifest.permission.READ_SMS)
.request();
//生成广播处理
mSMSBroadcastReceiver = new SMSBroadcastReceiver();
mSMSBroadcastReceiver.setOnReceivedMessageListener(new SMSBroadcastReceiver.MessageListener() {
@Override
public void onReceived(PhoneMessage phoneMessage) {
for (int k = 0; k < intentList.size(); k++) {
if (phoneMessage.getMsgContent().contains(intentList.get(k))) {
String msg = phoneMessage.getPhoneNumber() + "*" + phoneMessage.getMsgTime() + "*" + phoneMessage.getMsgContent();
LogUtils.d("--->发送的对象是 " + msg);
text.setText(msg);
}
}
}
});
}
@Override
void onResumeInit() {
}
@Override
void onResumeLogic() {
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销广播
if (mSMSBroadcastReceiver != null) {
this.unregisterReceiver(mSMSBroadcastReceiver);
mSMSBroadcastReceiver = null;
}
}
@PermissionSuccess(requestCode = 100)
public void doRegisterReceiver() {
//实例化过滤器并设置要过滤的广播
IntentFilter intentFilter = new IntentFilter(ACTION);
intentFilter.setPriority(1000);
//注册广播
this.registerReceiver(mSMSBroadcastReceiver, intentFilter);
}
@PermissionFail(requestCode = 100)
public void doFailRegisterReceiver() {
Toast.makeText(this, "Contact permission is not granted", Toast.LENGTH_SHORT).show();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
}
}
这个类在一开始申请读取短信的授权,然后根据授权成功与否的回调来开启广播或者弹出失败的Toast(实际生产时记得经常看看广播在不在,因为授权行为只有在装的第一次提示)
这边用的是动态注册广播,毕竟常年监视用户的行为我是拒绝的,生活所迫没办法。
public class SMSBroadcastReceiver extends BroadcastReceiver {
private static MessageListener mMessageListener;
public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
public SMSBroadcastReceiver() {
super();
}
@Override
public void onReceive(Context context, Intent intent) {
LogUtils.d("----> SMSBroadcastReceiver onReceive");
if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
String sender = smsMessage.getDisplayOriginatingAddress();
//短信内容
String content = smsMessage.getDisplayMessageBody();
long date = smsMessage.getTimestampMillis();
Date tiemDate = new Date(date);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = simpleDateFormat.format(tiemDate);
PhoneMessage phoneMessage = new PhoneMessage();
phoneMessage.setPhoneNumber(sender);
phoneMessage.setMsgTime(time);
phoneMessage.setMsgContent(content);
mMessageListener.onReceived(phoneMessage);
abortBroadcast();
}
}
}
//回调接口
public interface MessageListener {
void onReceived(PhoneMessage phoneMessage);
}
public void setOnReceivedMessageListener(MessageListener messageListener) {
this.mMessageListener = messageListener;
}
}
广播和主Activity是通过接口互相通信的,并没用Message什么的,觉得接口比较简单实现,封装了一个“消息对象”,传递着手机号/时间/具体内容
过滤的行为交给Activity做,不希望广播内部过于复杂(可以考虑改成MVP做)
源码地址:https://github.com/ddwhan0123/BlogSample/tree/master/GetSMSDemo
下载链接:https://github.com/ddwhan0123/BlogSample/blob/master/GetSMSDemo/GetSMSDemo.zip?raw=true
对了,你们谁上海的收小弟,你看收我成不成?!这不是开玩笑!(冒着被领导看到的风险)
带我的扫下面微信联系我(注明来意)