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 1fc13d7b..8d450793 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java +++ b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java @@ -27,10 +27,6 @@ public class MyApplication extends Application { public static List SimInfoList = new ArrayList<>(); //是否关闭页面提示 public static boolean showHelpTip = true; - //企业微信 - public static String QyWxAccessToken; - public static long QyWxAccessTokenExpiresIn = 0; - @Override protected void attachBaseContext(Context base) { 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 3626f4d4..67b81d44 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java +++ b/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java @@ -938,20 +938,23 @@ public class SenderActivity extends AppCompatActivity { show.dismiss(); }); buttonQYWXAppTest.setOnClickListener(view -> { - String cropID = editTextQYWXAppCorpID.getText().toString().trim(); - String agentID = editTextQYWXAppAgentID.getText().toString().trim(); - String secret = editTextQYWXAppSecret.getText().toString().trim(); - String toUser = editTextQYWXAppToUser.getText().toString().trim(); - //Boolean atAll = switchQYWXAppAtAll.isChecked(); - if (!toUser.isEmpty()) { - try { - SenderQyWxAppMsg.sendMsg(0, handler, cropID, agentID, secret, toUser, R.string.test_content + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())), true); - } catch (Exception e) { - Toast.makeText(SenderActivity.this, getString(R.string.failed_to_fwd) + e.getMessage(), Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } - } else { + + QYWXAppSettingVo QYWXAppSettingVoNew = new QYWXAppSettingVo( + editTextQYWXAppCorpID.getText().toString().trim(), + editTextQYWXAppAgentID.getText().toString().trim(), + editTextQYWXAppSecret.getText().toString().trim(), + editTextQYWXAppToUser.getText().toString().trim(), + switchQYWXAppAtAll.isChecked()); + if (QYWXAppSettingVoNew.getToUser().isEmpty()) { Toast.makeText(SenderActivity.this, R.string.invalid_at_mobiles, Toast.LENGTH_LONG).show(); + return; + } + + try { + SenderQyWxAppMsg.sendMsg(0, handler, senderModel, QYWXAppSettingVoNew, 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(); } }); } diff --git a/app/src/main/java/com/idormy/sms/forwarder/model/vo/QYWXAppSettingVo.java b/app/src/main/java/com/idormy/sms/forwarder/model/vo/QYWXAppSettingVo.java index 155a1a89..9a801909 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/model/vo/QYWXAppSettingVo.java +++ b/app/src/main/java/com/idormy/sms/forwarder/model/vo/QYWXAppSettingVo.java @@ -11,6 +11,8 @@ public class QYWXAppSettingVo implements Serializable { private String secret; private String toUser; private Boolean atAll; + private String accessToken; + private Long expiresIn; public QYWXAppSettingVo() { } @@ -23,4 +25,11 @@ public class QYWXAppSettingVo implements Serializable { this.atAll = atAll; } + public String getAccessToken() { + if (accessToken == null || accessToken.isEmpty() || expiresIn == null || System.currentTimeMillis() > expiresIn) { + return null; + } + return accessToken; + } + } 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 7cce4ee6..985c029a 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 @@ -193,7 +193,7 @@ public class SendUtil { QYWXAppSettingVo qYWXAppSettingVo = JSON.parseObject(senderModel.getJsonSetting(), QYWXAppSettingVo.class); if (qYWXAppSettingVo != null) { try { - SenderQyWxAppMsg.sendMsg(logId, handError, qYWXAppSettingVo.getCorpID(), qYWXAppSettingVo.getAgentID(), qYWXAppSettingVo.getSecret(), qYWXAppSettingVo.getToUser(), smsVo.getSmsVoForSend(smsTemplate), false); + SenderQyWxAppMsg.sendMsg(logId, handError, senderModel, qYWXAppSettingVo, smsVo.getSmsVoForSend(smsTemplate)); } catch (Exception e) { LogUtil.updateLog(logId, 0, e.getMessage()); Log.e(TAG, "senderSendMsg: qywx_app error " + e.getMessage()); diff --git a/app/src/main/java/com/idormy/sms/forwarder/sender/SenderQyWxAppMsg.java b/app/src/main/java/com/idormy/sms/forwarder/sender/SenderQyWxAppMsg.java index ea845fb9..1fcc0dfc 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/sender/SenderQyWxAppMsg.java +++ b/app/src/main/java/com/idormy/sms/forwarder/sender/SenderQyWxAppMsg.java @@ -11,7 +11,8 @@ import androidx.annotation.NonNull; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; -import com.idormy.sms.forwarder.MyApplication; +import com.idormy.sms.forwarder.model.SenderModel; +import com.idormy.sms.forwarder.model.vo.QYWXAppSettingVo; import com.idormy.sms.forwarder.utils.LogUtil; import com.idormy.sms.forwarder.utils.SettingUtil; @@ -36,127 +37,106 @@ public class SenderQyWxAppMsg extends SenderBaseMsg { static final String TAG = "SenderQyWxAppMsg"; - public static void sendMsg(final long logId, final Handler handError, String corpID, String agentID, String secret, String toUser, String content, boolean forceRefresh) throws Exception { - Log.i(TAG, "sendMsg corpID:" + corpID + " agentID:" + agentID + " secret:" + secret + " toUser:" + toUser + " content:" + content + " forceRefresh:" + forceRefresh); + public static void sendMsg(final long logId, final Handler handError, final SenderModel senderModel, final QYWXAppSettingVo qYWXAppSettingVo, String content) throws Exception { + + if (qYWXAppSettingVo == null) { + Toast(handError, TAG, "参数错误"); + return; + } + + String corpID = qYWXAppSettingVo.getCorpID(); + String agentID = qYWXAppSettingVo.getAgentID(); + String secret = qYWXAppSettingVo.getSecret(); + String toUser = qYWXAppSettingVo.getToUser(); + Boolean atAll = qYWXAppSettingVo.getAtAll(); + + Log.i(TAG, "sendMsg corpID:" + corpID + " agentID:" + agentID + " secret:" + secret + " toUser:" + toUser + " content:" + content); if (corpID == null || corpID.isEmpty() || agentID == null || agentID.isEmpty() || secret == null || secret.isEmpty()) { return; } - //TODO:判断access_token是否失效 - if (forceRefresh - || MyApplication.QyWxAccessToken == null || MyApplication.QyWxAccessToken.isEmpty() - || System.currentTimeMillis() > MyApplication.QyWxAccessTokenExpiresIn) { - String getTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"; - getTokenUrl += "corpid=" + corpID; - getTokenUrl += "&corpsecret=" + secret; - Log.d(TAG, "getTokenUrl:" + getTokenUrl); - - OkHttpClient client = new OkHttpClient(); - final Request request = new Request.Builder().url(getTokenUrl).get().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()); - Log.d(TAG, "onFailure:" + e.getMessage()); - if (handError != null) { - Message msg = new Message(); - msg.what = NOTIFY; - Bundle bundle = new Bundle(); - bundle.putString("DATA", "获取access_token失败:" + e.getMessage()); - msg.setData(bundle); - handError.sendMessage(msg); - } - } - - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - final String json = Objects.requireNonNull(response.body()).string(); - Log.d(TAG, "Code:" + response.code() + " Response: " + json); - JSONObject jsonObject = JSON.parseObject(json); - int errcode = jsonObject.getInteger("errcode"); - if (errcode == 0) { - MyApplication.QyWxAccessToken = jsonObject.getString("access_token"); - MyApplication.QyWxAccessTokenExpiresIn = System.currentTimeMillis() + (jsonObject.getInteger("expires_in") - 120) * 1000L; //提前2分钟过期 - Log.d(TAG, "access_token:" + MyApplication.QyWxAccessToken); - Log.d(TAG, "expires_in:" + MyApplication.QyWxAccessTokenExpiresIn); - - sendTextMsg(logId, handError, agentID, toUser, content); - } else { - String errmsg = jsonObject.getString("errmsg"); - LogUtil.updateLog(logId, 0, errmsg); - Log.d(TAG, "onFailure:" + errmsg); - if (handError != null) { - Message msg = new Message(); - msg.what = NOTIFY; - Bundle bundle = new Bundle(); - bundle.putString("DATA", "获取access_token失败:" + errmsg); - msg.setData(bundle); - handError.sendMessage(msg); - } - } - } - - }); - } else { - sendTextMsg(logId, handError, agentID, toUser, content); - } - - } - - //发送文本消息 - public static void sendTextMsg(final long logId, final Handler handError, String agentID, String toUser, String content) { - - Map textMsgMap = new HashMap(); - textMsgMap.put("touser", toUser); - textMsgMap.put("msgtype", "text"); - textMsgMap.put("agentid", agentID); - - Map textText = new HashMap(); - textText.put("content", content); - textMsgMap.put("text", textText); - - final String requestUrl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + MyApplication.QyWxAccessToken; - 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); + //TODO:获取有效access_token + String accessToken = qYWXAppSettingVo.getAccessToken(); + if (accessToken == null || accessToken.isEmpty()) { - 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("请求接口异常...")); - } + String getTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?"; + getTokenUrl += "corpid=" + corpID; + getTokenUrl += "&corpsecret=" + secret; + Log.d(TAG, "getTokenUrl:" + getTokenUrl); - @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); + OkHttpClient client = new OkHttpClient(); + final Request request = new Request.Builder().url(getTokenUrl).get().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()); + qYWXAppSettingVo.setAccessToken(""); + qYWXAppSettingVo.setExpiresIn(0L); + if (senderModel != null) { + senderModel.setJsonSetting(JSON.toJSONString(qYWXAppSettingVo)); + SenderUtil.updateSender(senderModel); + } + Log.d(TAG, "onFailure:" + e.getMessage()); + if (handError != null) { + Message msg = new Message(); + msg.what = NOTIFY; + Bundle bundle = new Bundle(); + bundle.putString("DATA", "获取access_token失败:" + e.getMessage()); + msg.setData(bundle); + handError.sendMessage(msg); - //TODO:粗略解析是否发送成功 - if (responseStr.contains("\"errcode\":0")) { - LogUtil.updateLog(logId, 1, responseStr); - } else { - LogUtil.updateLog(logId, 0, responseStr); + emitter.onError(new RuntimeException("请求接口异常...")); + } } - } - }); + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + final String json = Objects.requireNonNull(response.body()).string(); + Log.d(TAG, "Code:" + response.code() + " Response: " + json); + JSONObject jsonObject = JSON.parseObject(json); + int errcode = jsonObject.getInteger("errcode"); + if (errcode == 0) { + String access_token = jsonObject.getString("access_token"); + long expires_in = System.currentTimeMillis() + (jsonObject.getInteger("expires_in") - 120) * 1000L; //提前2分钟过期 + Log.d(TAG, "access_token:" + access_token); + Log.d(TAG, "expires_in:" + expires_in); + + qYWXAppSettingVo.setAccessToken(access_token); + qYWXAppSettingVo.setExpiresIn(expires_in); + if (senderModel != null) { + senderModel.setJsonSetting(JSON.toJSONString(qYWXAppSettingVo)); + SenderUtil.updateSender(senderModel); + } + + sendTextMsg(emitter, logId, handError, agentID, toUser, content, access_token); + } else { + String errmsg = jsonObject.getString("errmsg"); + LogUtil.updateLog(logId, 0, errmsg); + Log.d(TAG, "onFailure:" + errmsg); + if (handError != null) { + Message msg = new Message(); + msg.what = NOTIFY; + Bundle bundle = new Bundle(); + bundle.putString("DATA", "获取access_token失败:" + errmsg); + msg.setData(bundle); + handError.sendMessage(msg); + } + + emitter.onError(new RuntimeException("请求接口异常...")); + } + } + + }); + } else { + sendTextMsg(emitter, logId, handError, agentID, toUser, content, accessToken); + } + }).retryWhen((Observable errorObservable) -> errorObservable .zipWith(Observable.just( @@ -171,6 +151,59 @@ public class SenderQyWxAppMsg extends SenderBaseMsg { return Observable.timer(delay, TimeUnit.SECONDS); })) .subscribe(System.out::println); + + } + + //发送文本消息 + public static void sendTextMsg(ObservableEmitter emitter, final long logId, final Handler handError, String agentID, String toUser, String content, String accessToken) { + + Map textMsgMap = new HashMap(); + textMsgMap.put("touser", toUser); + textMsgMap.put("msgtype", "text"); + textMsgMap.put("agentid", agentID); + + Map textText = new HashMap(); + textText.put("content", content); + textMsgMap.put("text", textText); + + final String requestUrl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + accessToken; + Log.i(TAG, "requestUrl:" + requestUrl); + final String requestMsg = JSON.toJSONString(textMsgMap); + Log.i(TAG, "requestMsg:" + requestMsg); + + + 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("\"errcode\":0")) { + LogUtil.updateLog(logId, 1, responseStr); + } else { + LogUtil.updateLog(logId, 0, responseStr); + } + } + }); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/alert_dialog_setview_qywxapp.xml b/app/src/main/res/layout/alert_dialog_setview_qywxapp.xml index 4bd2c695..be2f2479 100644 --- a/app/src/main/res/layout/alert_dialog_setview_qywxapp.xml +++ b/app/src/main/res/layout/alert_dialog_setview_qywxapp.xml @@ -17,7 +17,7 @@ android:orientation="horizontal"> @@ -136,7 +136,8 @@ android:id="@+id/linearLayoutQYWXAppToUser" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> + android:orientation="vertical" + android:visibility="gone"> diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index f2bfcfd7..179b3c61 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -140,6 +140,7 @@ App Secret Is at all Specified Member + Tip:Specify members receive messages, member ID list (multiple recipients with \'|\' space, maximum 1000) WebHook, e.g. https://qyapi.weixin.qq.com/cgixx?key=xxx ServerChan\'s SendKey diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cc41bfb5..a3c2b801 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -135,11 +135,12 @@ 邮件主题 Webhook 地址 加签 Secret (没有可不填) - Corp ID - Agent ID - App Secret - 是否@所有人 + 企业ID + 应用AgentId + 应用Secret + 是否@all 指定成员 + Tip:指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个) 设置WebHook地址:示例:https://qyapi.weixin.qq.com/cgixx?key=xxx 设置Server酱·Turbo版的SendKey