diff --git a/.gitignore b/.gitignore index 4018676e..4a760c1a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ gradle.properties /app/release /keystore *.bak +/pic/working_principle.drawio diff --git a/README.md b/README.md index 527744c1..629b81f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SmsForwarder (短信转发器) -监控Android手机短信并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、手机短信等。 +短信转发器——监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。 > ⚠ 首发地址:https://github.com/pppscn/SmsForwarder @@ -24,7 +24,7 @@ ## 特点和准则: -* **简单** 只做两件事:监听短信 --> 根据指定规则转发 +* **简单** 只做两件事:监听手机短信/来电/APP通知 --> 根据指定规则转发 由此带来的好处: @@ -63,20 +63,20 @@ - [x] 接口请求失败后延时重试5次(可配置间隔时间,成功一次则终止重试) - [x] 转发到飞书机器人 - [x] 自定义 Scheme(forwarder://main)用于唤起App -- [x] 低电量预警(设置30%,则30、29时都通知一下,避免错过!按需设置一下转发规则(不再遍历所有发送方)【号码:88888888、内容:当前剩余电量:xx%,已经到达低电量预警阈值,请及时充电!、卡槽:sim1】) +- [x] 低电量预警(设置30%,则30、29时都通知一下,避免错过!按需设置一下转发规则(不再遍历所有发送通道)【号码:88888888、内容:当前剩余电量:xx%,已经到达低电量预警阈值,请及时充电!、卡槽:sim1】) - [x] 多语言支持(目前:中文、英文) - [x] 增加配置导出导入功能(一键克隆) - [x] 监听其他APP通知信息并转发 -- [x] 添加转发规则时允许自定义模板(留空则取全局设置) +- [x] 转发到PushPlus ### 使用流程: 1. 在Android手机上安装`SmsForwarder`本APP后点击应用图标打开 -2. 在设置发送方页面,添加或点击已添加的发送方来设置转发短信使用的方式,现在支持钉钉机器人、企业微信群机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱: - > 发送方配置见《发送方设置参考》章节 +2. 在设置发送通道页面,添加或点击已添加的发送通道来设置转发短信使用的方式,现在支持钉钉机器人、企业微信群机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱: + > 发送通道配置见《发送通道设置参考》章节 3. 在设置转发规则页面,添加或点击已添加的转发规则来设置转发什么样的短信,现在支持转发全部、根据手机号、根据短信内容、指定卡槽: + 当设置转发全部时,所以接收到的短信都会用转发出去。 - + 当设置根据手机号或短信内容时,请设置匹配的模式和值,例如:”手机号 是 10086 发送方选钉钉“。 + + 当设置根据手机号或短信内容时,请设置匹配的模式和值,例如:”手机号 是 10086 发送通道选钉钉“。 4. 点击主页面右上角的菜单可进入设置页面,在设置页面可以更新应用查看应用信息提交意见反馈等 5. 在主页面下拉可刷新转发的短信,点击清空记录可删除转发的记录 @@ -105,7 +105,7 @@ 4. adb进行授权 ```adb attach``` 然后允许授权 5. 配置定时任务每分钟执行命令 ```adb shell am start -n com.idormy.sms.forwarder/com.idormy.sms.forwarder.MainActivity``` -### 发送方设置参考 +### 发送通道设置参考 #### 钉钉机器人 @@ -186,21 +186,30 @@ * 【可选】安全设置->签名校验,复制到「加签 Secret」一栏 * 点击【测试】按钮验证一下 + +#### PushPlus + +* 前往 [PushPlus 官网](http://www.pushplus.plus) +* 根据自身需求选择 [一对一推送](http://www.pushplus.plus/push1.html) 或 [一对多推送](http://www.pushplus.plus/push2.html) +* 微信扫码登录,获取token,填写到「用户令牌」一栏 +* 【可选】其他可选参数参见 [一对多推送](http://www.pushplus.plus/doc/guide/api.html#%E4%B8%80%E3%80%81%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3) +* 点击【测试】按钮验证一下 + ### 应用截图: | 前台服务常驻状态栏 | 应用主界面 | 转发规则 | 转发详情 | | ---- | ---- | ---- | ---- | | ![前台服务常驻状态栏](pic/taskbar.jpg "前台服务常驻状态栏") | ![应用主界面](pic/main.png "应用主界面") | ![转发规则](pic/rule.jpg "转发规则") | ![转发详情](pic/maindetail.jpg "转发详情") | -| 添加/编辑转发规则测试 | 多重匹配规则 | 支持以下转发方式(发送方) | 添加/编辑发送方钉钉 | -| ![添加/编辑转发规则](pic/ruleset.png "添加/编辑转发规则") | ![多重匹配规则](pic/multimatch.png "多重匹配规则") | ![发送方](pic/sender.jpg "发送方") | ![添加/编辑发送方钉钉](pic/sendersetdingding.jpg "添加/编辑发送方钉钉") | -| 添加/编辑发送方邮箱 | 添加/编辑发送方Bark | 添加/编辑发送方网页通知 | 添加/编辑发送方企业微信群机器人 | -| ![添加/编辑发送方邮箱](pic/sendersetemail.jpg "添加/编辑发送方邮箱") | ![添加/编辑发送方Bark](pic/sendersetbark.png "添加/编辑发送方Bark") | ![添加/编辑发送方网页通知](pic/sendersetwebnotify.jpg "添加/编辑发送方网页通知") | ![添加/编辑发送方企业微信群机器人](pic/sendersetqywechat.jpg "添加/编辑发送方企业微信群机器人") | -| 添加/编辑发送方Telegram机器人 | 添加/编辑发送方Server酱·Turbo版 | 添加/编辑发送方企业微信应用 | 应用设置 | -| ![添加/编辑发送方Telegram机器人](pic/sendertelegram.jpg "添加/编辑发送方Telegram机器人") | ![添加/编辑发送方Server酱·Turbo版](pic/senderserverchan.jpg "添加/编辑发送方Server酱·Turbo版") | ![添加/编辑发送方企业微信应用](pic/sendersetqywxapp.jpg "添加/编辑发送方企业微信应用") | ![应用设置](pic/setting.jpg "应用设置") | -| 关于/在线升级 | 支持正则匹配规则 & 支持卡槽匹配规则 | 转发短信模板增加卡槽标识 | 添加/编辑发送方其他手机短信 | -| ![在线升级](pic/update.jpg "在线升级") | ![支持正则匹配规则 & 支持卡槽匹配规则](pic/regex.jpg "支持正则匹配规则 & 支持卡槽匹配规则") | ![转发短信模板增加卡槽标识](pic/siminfo.jpg "转发短信模板增加卡槽标识") | ![添加/编辑发送方其他手机短信](pic/sendersetsms.jpg "添加/编辑发送方其他手机短信") | -| 添加/编辑发送方飞书机器人 | 增加配置导出导入功能(一键克隆) | 监听其他APP通知信息并转发 | 获取所有应用列表(方便复制APP包名)| -| ![添加/编辑发送方飞书](pic/senderfeishu.png "添加/编辑发送方飞书") | ![增加配置导出导入功能(一键克隆)](pic/clone.png "增加配置导出导入功能(一键克隆)") | ![监听其他APP通知信息并转发](pic/app_notify.png "监听其他APP通知信息并转发") | ![获取所有应用列表(方便复制APP包名)](pic/app_list.png "获取所有应用列表(方便复制APP包名)") | +| 添加/编辑转发规则测试 | 多重匹配规则 | 支持以下转发方式(发送通道) | 添加/编辑发送通道钉钉 | +| ![添加/编辑转发规则](pic/ruleset.png "添加/编辑转发规则") | ![多重匹配规则](pic/multimatch.png "多重匹配规则") | ![发送通道](pic/sender.jpg "发送通道") | ![添加/编辑发送通道钉钉](pic/sendersetdingding.jpg "添加/编辑发送通道钉钉") | +| 添加/编辑发送通道邮箱 | 添加/编辑发送通道Bark | 添加/编辑发送通道网页通知 | 添加/编辑发送通道企业微信群机器人 | +| ![添加/编辑发送通道邮箱](pic/sendersetemail.jpg "添加/编辑发送通道邮箱") | ![添加/编辑发送通道Bark](pic/sendersetbark.png "添加/编辑发送通道Bark") | ![添加/编辑发送通道网页通知](pic/sendersetwebnotify.jpg "添加/编辑发送通道网页通知") | ![添加/编辑发送通道企业微信群机器人](pic/sendersetqywechat.jpg "添加/编辑发送通道企业微信群机器人") | +| 添加/编辑发送通道Telegram机器人 | 添加/编辑发送通道Server酱·Turbo版 | 添加/编辑发送通道企业微信应用 | 应用设置 | +| ![添加/编辑发送通道Telegram机器人](pic/sendertelegram.jpg "添加/编辑发送通道Telegram机器人") | ![添加/编辑发送通道Server酱·Turbo版](pic/senderserverchan.jpg "添加/编辑发送通道Server酱·Turbo版") | ![添加/编辑发送通道企业微信应用](pic/sendersetqywxapp.jpg "添加/编辑发送通道企业微信应用") | ![应用设置](pic/setting.jpg "应用设置") | +| 关于/在线升级 | 支持正则匹配规则 & 支持卡槽匹配规则 | 转发短信模板增加卡槽标识 | 添加/编辑发送通道其他手机短信 | +| ![在线升级](pic/update.jpg "在线升级") | ![支持正则匹配规则 & 支持卡槽匹配规则](pic/regex.jpg "支持正则匹配规则 & 支持卡槽匹配规则") | ![转发短信模板增加卡槽标识](pic/siminfo.jpg "转发短信模板增加卡槽标识") | ![添加/编辑发送通道其他手机短信](pic/sendersetsms.jpg "添加/编辑发送通道其他手机短信") | +| 添加/编辑发送通道飞书机器人 | 增加配置导出导入功能(一键克隆) | 监听其他APP通知信息并转发 | 获取所有应用列表(方便复制APP包名)| +| ![添加/编辑发送通道飞书](pic/senderfeishu.png "添加/编辑发送通道飞书") | ![增加配置导出导入功能(一键克隆)](pic/clone.png "增加配置导出导入功能(一键克隆)") | ![监听其他APP通知信息并转发](pic/app_notify.png "监听其他APP通知信息并转发") | ![获取所有应用列表(方便复制APP包名)](pic/app_list.png "获取所有应用列表(方便复制APP包名)") | -------- @@ -228,14 +237,14 @@ + [v1.6.4] Android8.1以下手机重启后尝试启动主界面,以便动态获取权限(修复开机自启后无法转发短信,要打开软件后才会转发短信的问题) + [v1.7.0] 新增转发到其他手机短信 & 避免热插卡时FC & 规则展示优化 & 获取多卡信息&获取卡槽备注优化 & 新增恢复初始化配置 + [v1.7.1] 新增转发记录的转发状态(成功/失败&应答信息) - + [v1.7.2] 新增V1版证书签名,避免部分低版本系统(Android 6.x)无证书错误 & 发送方邮箱允许自定义发件人昵称 + + [v1.7.2] 新增V1版证书签名,避免部分低版本系统(Android 6.x)无证书错误 & 发送通道邮箱允许自定义发件人昵称 + [v1.7.3] 修复“设置匹配模式”默认选择BUG & 转发到webhook时返回http状态200即为成功 & 转发到其他手机短信支持长短信合并 - + [v1.7.4] 修复转发企业微信群机器人碰到"被截断问题 & 转发到webhook时忽略ssl证书校验(提高自建服务端兼容性) & 转发telegram时将 # 替换为 井,避免被当作标签 & 隐私保护,发送方设置中敏感信息(密码/token/secret等)用星号显示 & 更新友盟基础组件库 & 解决“设置页面关闭卡槽信息,同时使用默认模板时,发送消息卡槽信息仍显示” + + [v1.7.4] 修复转发企业微信群机器人碰到"被截断问题 & 转发到webhook时忽略ssl证书校验(提高自建服务端兼容性) & 转发telegram时将 # 替换为 井,避免被当作标签 & 隐私保护,发送通道设置中敏感信息(密码/token/secret等)用星号显示 & 更新友盟基础组件库 & 解决“设置页面关闭卡槽信息,同时使用默认模板时,发送消息卡槽信息仍显示” + [v2.0.0] 来电提醒转发 & 接口请求失败后延时重试5次(可配置间隔时间)& 转发到飞书机器人 & 自定义 Scheme(forwarder://main)用于唤起App & 低电量预警 & 重新梳理代码(消灭waring)& Bark增加支持分组 & 引入Lombok & 升级gradle版本 & 增加电池优化白名单设置和权限 & 转发到webhook增加支持自定义post数据,并支持Json数据提交 - + [v2.0.1] 改进低电量预警方式,按需设置一下转发规则(不再遍历所有发送方)【号码:88888888、内容:当前剩余电量:xx%,已经到达低电量预警阈值,请及时充电!、卡槽:sim1】 + + [v2.0.1] 改进低电量预警方式,按需设置一下转发规则(不再遍历所有发送通道)【号码:88888888、内容:当前剩余电量:xx%,已经到达低电量预警阈值,请及时充电!、卡槽:sim1】 + [v2.1.0] 增加配置导出导入功能(一键克隆) & bark新增指定推送消息图标 & 简化设置,取消“转发时附加卡槽信息”和“转发时附加设备名称”开关,若需要直接修改“转发信息模板” & 修复转发未接来电开关失效问题 + [v2.1.1] fix:自定义模板&匹配的值输入框支持多行文本 & fix:取消“转发时附加卡槽信息”和“转发时附加设备名称”开关 -+ [v2.2.0] 新增:监听其他APP通知信息并根据规则转发 & 修复Telegram手机号丢失问题 & 优化:来电转发增加获取卡槽信息 & 优化:Telegram转发支持自定义bot地址(复用ApiToken字段,http开头) & 新增:添加转发规则时允许自定义模板(留空则取全局设置) & 修复:bark指定推送消息图标空指针判断bug & 新增:转发短信总开关 & 优化:ActionBar弹出菜单的位置 & 新增:获取所有应用列表(方便复制APP包名) ++ [v2.2.0] 新增:监听其他APP通知信息并根据规则转发 & 修复Telegram手机号丢失问题 & 优化:来电转发增加获取卡槽信息 & 优化:Telegram转发支持自定义bot地址(复用ApiToken字段,http开头) & 新增:添加转发规则时允许自定义模板(留空则取全局设置) & 修复:bark指定推送消息图标空指针判断bug & 新增:转发短信总开关 & 优化:ActionBar弹出菜单的位置 & 新增:获取所有应用列表(方便复制APP包名) & 新增:转发到PushPlus & 新增:帮助文档(跳转Gitee的wiki)& 优化:不在最近任务列表中显示(利于措施) -------- @@ -257,7 +266,6 @@ + https://github.com/xuexiangjys/XUpdateAPI (在线升级) + https://github.com/mailhu/emailkit (邮件发送) + https://github.com/alibaba/fastjson (Json解析) -+ https://github.com/lilongweidev/NotifyListenerDemo (手机通知服务) ## LICENSE diff --git a/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java b/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java index 3c1999cc..e04170cd 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java +++ b/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java @@ -148,9 +148,7 @@ public class AppListActivity extends AppCompatActivity { // 通过packName得到PackageInfo,作为参数传入即可 private boolean isSystemApp(PackageInfo pi) { - boolean isSysApp = (pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1; - boolean isSysUpd = (pi.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1; - return isSysApp || isSysUpd; + return (pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1; } @Override diff --git a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java index 47094d97..1fc13d7b 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java +++ b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java @@ -65,7 +65,7 @@ public class MyApplication extends Application { SharedPreferences sp = MyApplication.this.getSharedPreferences(Define.SP_CONFIG, Context.MODE_PRIVATE); showHelpTip = sp.getBoolean(Define.SP_CONFIG_SWITCH_HELP_TIP, true); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SettingUtil.getExcludeFromRecents()) { + if (SettingUtil.getExcludeFromRecents()) { ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); if (am != null) { List appTasks = am.getAppTasks(); diff --git a/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java b/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java index f3b2e127..0d06f692 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java +++ b/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java @@ -5,6 +5,7 @@ import static com.idormy.sms.forwarder.model.SenderModel.TYPE_BARK; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_DINGDING; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_EMAIL; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_FEISHU; +import static com.idormy.sms.forwarder.model.SenderModel.TYPE_PUSHPLUS; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_APP; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_GROUP_ROBOT; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_SERVER_CHAN; @@ -37,6 +38,7 @@ import com.idormy.sms.forwarder.model.vo.BarkSettingVo; import com.idormy.sms.forwarder.model.vo.DingDingSettingVo; import com.idormy.sms.forwarder.model.vo.EmailSettingVo; import com.idormy.sms.forwarder.model.vo.FeiShuSettingVo; +import com.idormy.sms.forwarder.model.vo.PushPlusSettingVo; import com.idormy.sms.forwarder.model.vo.QYWXAppSettingVo; import com.idormy.sms.forwarder.model.vo.QYWXGroupRobotSettingVo; import com.idormy.sms.forwarder.model.vo.ServerChanSettingVo; @@ -47,6 +49,7 @@ import com.idormy.sms.forwarder.sender.SenderBarkMsg; import com.idormy.sms.forwarder.sender.SenderDingdingMsg; import com.idormy.sms.forwarder.sender.SenderFeishuMsg; import com.idormy.sms.forwarder.sender.SenderMailMsg; +import com.idormy.sms.forwarder.sender.SenderPushPlusMsg; import com.idormy.sms.forwarder.sender.SenderQyWxAppMsg; import com.idormy.sms.forwarder.sender.SenderQyWxGroupRobotMsg; import com.idormy.sms.forwarder.sender.SenderServerChanMsg; @@ -142,6 +145,9 @@ public class SenderActivity extends AppCompatActivity { case TYPE_FEISHU: setFeiShu(senderModel); break; + case TYPE_PUSHPLUS: + setPushPlus(senderModel); + break; default: Toast.makeText(SenderActivity.this, R.string.invalid_sender, Toast.LENGTH_LONG).show(); SenderUtil.delSender(senderModel.getId()); @@ -217,6 +223,9 @@ public class SenderActivity extends AppCompatActivity { case TYPE_FEISHU: setFeiShu(null); break; + case TYPE_PUSHPLUS: + setPushPlus(null); + break; default: Toast.makeText(SenderActivity.this, R.string.not_supported, Toast.LENGTH_LONG).show(); break; @@ -1180,6 +1189,119 @@ public class SenderActivity extends AppCompatActivity { }); } + //推送加 + @SuppressLint("SimpleDateFormat") + private void setPushPlus(final SenderModel senderModel) { + PushPlusSettingVo pushPlusSettingVo = null; + //try phrase json setting + if (senderModel != null) { + String jsonSettingStr = senderModel.getJsonSetting(); + if (jsonSettingStr != null) { + pushPlusSettingVo = JSON.parseObject(jsonSettingStr, PushPlusSettingVo.class); + } + } + final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this); + View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_pushplus, null); + + final EditText editTextPushPlusName = view1.findViewById(R.id.editTextPushPlusName); + final EditText editTextPushPlusToken = view1.findViewById(R.id.editTextPushPlusToken); + final EditText editTextPushPlusTopic = view1.findViewById(R.id.editTextPushPlusTopic); + final EditText editTextPushPlusTemplate = view1.findViewById(R.id.editTextPushPlusTemplate); + final EditText editTextPushPlusChannel = view1.findViewById(R.id.editTextPushPlusChannel); + final EditText editTextPushPlusWebhook = view1.findViewById(R.id.editTextPushPlusWebhook); + final EditText editTextPushPlusCallbackUrl = view1.findViewById(R.id.editTextPushPlusCallbackUrl); + + if (pushPlusSettingVo != null) { + editTextPushPlusName.setText(senderModel.getName()); + editTextPushPlusToken.setText(pushPlusSettingVo.getToken()); + editTextPushPlusTopic.setText(pushPlusSettingVo.getTopic()); + editTextPushPlusTemplate.setText(pushPlusSettingVo.getTemplate()); + editTextPushPlusChannel.setText(pushPlusSettingVo.getChannel()); + editTextPushPlusWebhook.setText(pushPlusSettingVo.getWebhook()); + editTextPushPlusCallbackUrl.setText(pushPlusSettingVo.getCallbackUrl()); + } + + Button buttonPushPlusOk = view1.findViewById(R.id.buttonPushPlusOk); + Button buttonPushPlusDel = view1.findViewById(R.id.buttonPushPlusDel); + Button buttonPushPlusTest = view1.findViewById(R.id.buttonPushPlusTest); + alertDialog71 + .setTitle(R.string.setpushplustitle) + .setIcon(R.mipmap.pushplus) + .setView(view1) + .create(); + final AlertDialog show = alertDialog71.show(); + buttonPushPlusOk.setOnClickListener(view -> { + + if (senderModel == null) { + SenderModel newSenderModel = new SenderModel(); + newSenderModel.setName(editTextPushPlusName.getText().toString()); + newSenderModel.setType(TYPE_PUSHPLUS); + newSenderModel.setStatus(STATUS_ON); + PushPlusSettingVo pushPlusSettingVoNew = new PushPlusSettingVo( + editTextPushPlusToken.getText().toString(), + editTextPushPlusTopic.getText().toString(), + editTextPushPlusTemplate.getText().toString(), + editTextPushPlusChannel.getText().toString(), + editTextPushPlusWebhook.getText().toString(), + editTextPushPlusCallbackUrl.getText().toString() + ); + newSenderModel.setJsonSetting(JSON.toJSONString(pushPlusSettingVoNew)); + SenderUtil.addSender(newSenderModel); + initSenders(); + adapter.add(senderModels); + } else { + senderModel.setName(editTextPushPlusName.getText().toString()); + senderModel.setType(TYPE_PUSHPLUS); + senderModel.setStatus(STATUS_ON); + PushPlusSettingVo pushPlusSettingVoNew = new PushPlusSettingVo( + editTextPushPlusToken.getText().toString(), + editTextPushPlusTopic.getText().toString(), + editTextPushPlusTemplate.getText().toString(), + editTextPushPlusChannel.getText().toString(), + editTextPushPlusWebhook.getText().toString(), + editTextPushPlusCallbackUrl.getText().toString() + ); + senderModel.setJsonSetting(JSON.toJSONString(pushPlusSettingVoNew)); + SenderUtil.updateSender(senderModel); + initSenders(); + adapter.update(senderModels); + } + show.dismiss(); + }); + + buttonPushPlusDel.setOnClickListener(view -> { + if (senderModel != null) { + SenderUtil.delSender(senderModel.getId()); + initSenders(); + adapter.del(senderModels); + } + show.dismiss(); + }); + + buttonPushPlusTest.setOnClickListener(view -> { + PushPlusSettingVo pushPlusSettingVoNew = new PushPlusSettingVo( + editTextPushPlusToken.getText().toString(), + editTextPushPlusTopic.getText().toString(), + editTextPushPlusTemplate.getText().toString(), + editTextPushPlusChannel.getText().toString(), + editTextPushPlusWebhook.getText().toString(), + editTextPushPlusCallbackUrl.getText().toString() + ); + + String token = pushPlusSettingVoNew.getToken(); + if (token != null && !token.isEmpty()) { + try { + SenderPushPlusMsg.sendMsg(0, handler, pushPlusSettingVoNew, "SmsForwarder", getString(R.string.test_content) + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))); + } catch (Exception e) { + Toast.makeText(SenderActivity.this, getString(R.string.failed_to_fwd) + e.getMessage(), Toast.LENGTH_LONG).show(); + e.printStackTrace(); + } + } else { + Toast.makeText(SenderActivity.this, R.string.invalid_token, Toast.LENGTH_LONG).show(); + } + }); + } + @Override protected void onDestroy() { Log.d(TAG, "onDestroy"); diff --git a/app/src/main/java/com/idormy/sms/forwarder/model/SenderModel.java b/app/src/main/java/com/idormy/sms/forwarder/model/SenderModel.java index de2b8738..baa3673d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/model/SenderModel.java +++ b/app/src/main/java/com/idormy/sms/forwarder/model/SenderModel.java @@ -21,6 +21,7 @@ public class SenderModel { public static final int TYPE_TELEGRAM = 7; public static final int TYPE_SMS = 8; public static final int TYPE_FEISHU = 9; + public static final int TYPE_PUSHPLUS = 10; private Long id; private String name; private int status; @@ -58,6 +59,8 @@ public class SenderModel { return R.mipmap.telegram; case (TYPE_FEISHU): return R.mipmap.feishu; + case (TYPE_PUSHPLUS): + return R.mipmap.pushplus; case (TYPE_SMS): default: return R.mipmap.sms; @@ -84,6 +87,8 @@ public class SenderModel { return R.mipmap.telegram; case (TYPE_FEISHU): return R.mipmap.feishu; + case (TYPE_PUSHPLUS): + return R.mipmap.pushplus; case (TYPE_SMS): default: return R.mipmap.sms; diff --git a/app/src/main/java/com/idormy/sms/forwarder/model/vo/PushPlusSettingVo.java b/app/src/main/java/com/idormy/sms/forwarder/model/vo/PushPlusSettingVo.java new file mode 100644 index 00000000..cc52a0d1 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/model/vo/PushPlusSettingVo.java @@ -0,0 +1,27 @@ +package com.idormy.sms.forwarder.model.vo; + +import java.io.Serializable; + +import lombok.Data; + +@Data +public class PushPlusSettingVo implements Serializable { + private String token; + private String topic; + private String template; + private String channel; + private String webhook; + private String callbackUrl; + + public PushPlusSettingVo() { + } + + public PushPlusSettingVo(String token, String topic, String template, String channel, String webhook, String callbackUrl) { + this.token = token; + this.topic = topic; + this.template = template; + this.channel = channel; + this.webhook = webhook; + this.callbackUrl = callbackUrl; + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java b/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java index 6614659a..28895c8f 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java +++ b/app/src/main/java/com/idormy/sms/forwarder/sender/SendUtil.java @@ -4,6 +4,7 @@ import static com.idormy.sms.forwarder.model.SenderModel.TYPE_BARK; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_DINGDING; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_EMAIL; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_FEISHU; +import static com.idormy.sms.forwarder.model.SenderModel.TYPE_PUSHPLUS; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_APP; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_GROUP_ROBOT; import static com.idormy.sms.forwarder.model.SenderModel.TYPE_SERVER_CHAN; @@ -23,6 +24,7 @@ import com.idormy.sms.forwarder.model.vo.BarkSettingVo; import com.idormy.sms.forwarder.model.vo.DingDingSettingVo; import com.idormy.sms.forwarder.model.vo.EmailSettingVo; import com.idormy.sms.forwarder.model.vo.FeiShuSettingVo; +import com.idormy.sms.forwarder.model.vo.PushPlusSettingVo; import com.idormy.sms.forwarder.model.vo.QYWXAppSettingVo; import com.idormy.sms.forwarder.model.vo.QYWXGroupRobotSettingVo; import com.idormy.sms.forwarder.model.vo.ServerChanSettingVo; @@ -272,6 +274,21 @@ public class SendUtil { } break; + case TYPE_PUSHPLUS: + //try phrase json setting + if (senderModel.getJsonSetting() != null) { + PushPlusSettingVo pushPlusSettingVo = JSON.parseObject(senderModel.getJsonSetting(), PushPlusSettingVo.class); + if (pushPlusSettingVo != null) { + try { + SenderPushPlusMsg.sendMsg(logId, handError, pushPlusSettingVo, smsVo.getMobile(), smsVo.getSmsVoForSend(smsTemplate)); + } catch (Exception e) { + LogUtil.updateLog(logId, 0, e.getMessage()); + Log.e(TAG, "senderSendMsg: feishu error " + e.getMessage()); + } + } + } + break; + default: break; } diff --git a/app/src/main/java/com/idormy/sms/forwarder/sender/SenderPushPlusMsg.java b/app/src/main/java/com/idormy/sms/forwarder/sender/SenderPushPlusMsg.java new file mode 100644 index 00000000..2c8801ab --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/sender/SenderPushPlusMsg.java @@ -0,0 +1,128 @@ +package com.idormy.sms.forwarder.sender; + +import android.os.Handler; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.alibaba.fastjson.JSON; +import com.idormy.sms.forwarder.model.vo.PushPlusSettingVo; +import com.idormy.sms.forwarder.utils.LogUtil; +import com.idormy.sms.forwarder.utils.SettingUtil; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.ObservableEmitter; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +@SuppressWarnings({"ResultOfMethodCallIgnored", "rawtypes", "unchecked", "deprecation"}) +public class SenderPushPlusMsg extends SenderBaseMsg { + + static final String TAG = "SenderFeishuMsg"; + + public static void sendMsg(final long logId, final Handler handError, PushPlusSettingVo pushPlusSettingVo, String title, String content) throws Exception { + + //用户令牌 + String token = pushPlusSettingVo.getToken(); + if (token == null || token.isEmpty()) return; + + Map textMsgMap = new HashMap(); + + //消息标题 + if (title != null && !title.isEmpty()) textMsgMap.put("title", title); + + //具体消息内容 + if (content == null || content.isEmpty()) return; + textMsgMap.put("content", content); + + //群组编码,不填仅发送给自己;channel为webhook时无效 + String topic = pushPlusSettingVo.getTopic(); + if (topic != null && !topic.isEmpty()) textMsgMap.put("topic", topic); + + //发送模板 + String template = pushPlusSettingVo.getTemplate(); + if (template != null && !template.isEmpty()) textMsgMap.put("template", template); + + //发送渠道 + String channel = pushPlusSettingVo.getChannel(); + if (channel != null && !channel.isEmpty()) textMsgMap.put("channel", channel); + + //webhook编码,仅在channel使用webhook渠道和CP渠道时需要填写 + String webhook = pushPlusSettingVo.getChannel(); + if (webhook != null && !webhook.isEmpty()) textMsgMap.put("webhook", webhook); + + //发送结果回调地址 + String callbackUrl = pushPlusSettingVo.getCallbackUrl(); + if (callbackUrl != null && !callbackUrl.isEmpty()) textMsgMap.put("callbackUrl", callbackUrl); + + //毫秒时间戳。格式如:1632993318000。服务器时间戳大于此时间戳,则消息不会发送 + textMsgMap.put("timestamp", System.currentTimeMillis()); + + final String requestUrl = "http://www.pushplus.plus/send/" + token; + Log.i(TAG, "requestUrl:" + requestUrl); + final String requestMsg = JSON.toJSONString(textMsgMap); + Log.i(TAG, "requestMsg:" + requestMsg); + + Observable + .create((ObservableEmitter emitter) -> { + Toast(handError, TAG, "开始请求接口..."); + + OkHttpClient client = new OkHttpClient(); + RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), requestMsg); + + final Request request = new Request.Builder() + .url(requestUrl) + .addHeader("Content-Type", "application/json; charset=utf-8") + .post(requestBody) + .build(); + Call call = client.newCall(request); + call.enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull final IOException e) { + LogUtil.updateLog(logId, 0, e.getMessage()); + Toast(handError, TAG, "发送失败:" + e.getMessage()); + emitter.onError(new RuntimeException("请求接口异常...")); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + final String responseStr = Objects.requireNonNull(response.body()).string(); + Log.d(TAG, "Response:" + response.code() + "," + responseStr); + Toast(handError, TAG, "发送状态:" + responseStr); + + //TODO:粗略解析是否发送成功 + if (responseStr.contains("\"code\":200")) { + LogUtil.updateLog(logId, 1, responseStr); + } else { + LogUtil.updateLog(logId, 0, responseStr); + } + } + }); + + }).retryWhen((Observable errorObservable) -> errorObservable + .zipWith(Observable.just( + SettingUtil.getRetryDelayTime(1), + SettingUtil.getRetryDelayTime(2), + SettingUtil.getRetryDelayTime(3), + SettingUtil.getRetryDelayTime(4), + SettingUtil.getRetryDelayTime(5) + ), (Throwable e, Integer time) -> time) + .flatMap((Integer delay) -> { + Toast(handError, TAG, "请求接口异常," + delay + "秒后重试"); + return Observable.timer(delay, TimeUnit.SECONDS); + })) + .subscribe(System.out::println); + } + +} diff --git a/app/src/main/res/layout/activity_rule.xml b/app/src/main/res/layout/activity_rule.xml index 8db9e5c5..5c3c25bd 100644 --- a/app/src/main/res/layout/activity_rule.xml +++ b/app/src/main/res/layout/activity_rule.xml @@ -1,5 +1,6 @@ @@ -86,7 +87,8 @@ android:onClick="addRule" android:tag="sms" android:padding="0dp" - android:text="@string/new_sms_rule" /> + android:text="@string/new_sms_rule" + tools:ignore="ButtonStyle,UsingOnClickInXml" />