新增:Gotify发送通道(自主推送通知服务)

pull/115/head
pppscn 3 years ago
parent 45cfe6cff8
commit ec726ca8d2

@ -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_GOTIFY;
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;
@ -38,6 +39,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.GotifySettingVo;
import com.idormy.sms.forwarder.model.vo.PushPlusSettingVo;
import com.idormy.sms.forwarder.model.vo.QYWXAppSettingVo;
import com.idormy.sms.forwarder.model.vo.QYWXGroupRobotSettingVo;
@ -48,6 +50,7 @@ import com.idormy.sms.forwarder.model.vo.WebNotifySettingVo;
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.SenderGotifyMsg;
import com.idormy.sms.forwarder.sender.SenderMailMsg;
import com.idormy.sms.forwarder.sender.SenderPushPlusMsg;
import com.idormy.sms.forwarder.sender.SenderQyWxAppMsg;
@ -149,6 +152,9 @@ public class SenderActivity extends AppCompatActivity {
case TYPE_PUSHPLUS:
setPushPlus(senderModel, false);
break;
case TYPE_GOTIFY:
setGotify(senderModel, false);
break;
default:
Toast.makeText(SenderActivity.this, R.string.invalid_sender, Toast.LENGTH_LONG).show();
SenderUtil.delSender(senderModel.getId());
@ -209,6 +215,9 @@ public class SenderActivity extends AppCompatActivity {
case TYPE_PUSHPLUS:
setPushPlus(senderModel, true);
break;
case TYPE_GOTIFY:
setGotify(senderModel, true);
break;
default:
Toast.makeText(SenderActivity.this, R.string.invalid_sender, Toast.LENGTH_LONG).show();
SenderUtil.delSender(senderModel.getId());
@ -272,6 +281,9 @@ public class SenderActivity extends AppCompatActivity {
case TYPE_PUSHPLUS:
setPushPlus(null, false);
break;
case TYPE_GOTIFY:
setGotify(null, false);
break;
default:
Toast.makeText(SenderActivity.this, R.string.not_supported, Toast.LENGTH_LONG).show();
break;
@ -1472,6 +1484,140 @@ public class SenderActivity extends AppCompatActivity {
});
}
//Gotify
@SuppressLint("SimpleDateFormat")
private void setGotify(final SenderModel senderModel, final boolean isClone) {
GotifySettingVo gotifySettingVo = null;
//try phrase json setting
if (senderModel != null) {
String jsonSettingStr = senderModel.getJsonSetting();
if (jsonSettingStr != null) {
gotifySettingVo = JSON.parseObject(jsonSettingStr, GotifySettingVo.class);
}
}
final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_gotify, null);
final EditText editTextGotifyName = view1.findViewById(R.id.editTextGotifyName);
if (senderModel != null) editTextGotifyName.setText(senderModel.getName());
final EditText editTextGotifyWebServer = view1.findViewById(R.id.editTextGotifyWebServer);
final EditText editTextGotifyTitle = view1.findViewById(R.id.editTextGotifyTitle);
final EditText editTextGotifyPriority = view1.findViewById(R.id.editTextGotifyPriority);
if (gotifySettingVo != null) {
editTextGotifyWebServer.setText(gotifySettingVo.getWebServer());
editTextGotifyTitle.setText(gotifySettingVo.getTitle());
editTextGotifyPriority.setText(gotifySettingVo.getPriority());
}
Button buttonGotifyOk = view1.findViewById(R.id.buttonGotifyOk);
Button buttonGotifyDel = view1.findViewById(R.id.buttonGotifyDel);
Button buttonGotifyTest = view1.findViewById(R.id.buttonGotifyTest);
alertDialog71
.setTitle(R.string.setgotifytitle)
.setIcon(R.mipmap.gotify)
.setView(view1)
.create();
final AlertDialog show = alertDialog71.show();
buttonGotifyOk.setOnClickListener(view -> {
String webServer = editTextGotifyWebServer.getText().toString().trim();
if (webServer.isEmpty()) {
Toast.makeText(SenderActivity.this, R.string.invalid_webserver, Toast.LENGTH_LONG).show();
return;
}
String title = editTextGotifyTitle.getText().toString().trim();
if (title.isEmpty()) title = "SmsForwarder Title";
String priority = editTextGotifyPriority.getText().toString().trim();
GotifySettingVo gotifySettingVoNew = new GotifySettingVo(webServer, title, priority);
if (isClone || senderModel == null) {
SenderModel newSenderModel = new SenderModel();
newSenderModel.setName(editTextGotifyName.getText().toString().trim());
newSenderModel.setType(TYPE_GOTIFY);
newSenderModel.setStatus(STATUS_ON);
newSenderModel.setJsonSetting(JSON.toJSONString(gotifySettingVoNew));
SenderUtil.addSender(newSenderModel);
initSenders();
adapter.add(senderModels);
} else {
senderModel.setName(editTextGotifyName.getText().toString().trim());
senderModel.setType(TYPE_GOTIFY);
senderModel.setStatus(STATUS_ON);
senderModel.setJsonSetting(JSON.toJSONString(gotifySettingVoNew));
SenderUtil.updateSender(senderModel);
initSenders();
adapter.update(senderModels);
}
show.dismiss();
});
buttonGotifyDel.setOnClickListener(view -> {
if (senderModel != null) {
SenderUtil.delSender(senderModel.getId());
initSenders();
adapter.del(senderModels);
}
show.dismiss();
});
buttonGotifyTest.setOnClickListener(view -> {
String webServer = editTextGotifyWebServer.getText().toString().trim();
if (webServer.isEmpty()) {
Toast.makeText(SenderActivity.this, R.string.invalid_webserver, Toast.LENGTH_LONG).show();
return;
}
String title = editTextGotifyTitle.getText().toString().trim();
if (title.isEmpty()) title = "SmsForwarder Title";
String priority = editTextGotifyPriority.getText().toString().trim();
GotifySettingVo gotifySettingVoNew = new GotifySettingVo(webServer, title, priority);
try {
SenderGotifyMsg.sendMsg(0, handler, gotifySettingVoNew, title, 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();
}
});
Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
buttonInsertSender.setOnClickListener(view -> {
editTextGotifyTitle.setFocusable(true);
editTextGotifyTitle.requestFocus();
editTextGotifyTitle.append("{{来源号码}}");
});
Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
buttonInsertExtra.setOnClickListener(view -> {
editTextGotifyTitle.setFocusable(true);
editTextGotifyTitle.requestFocus();
editTextGotifyTitle.append("{{卡槽信息}}");
});
Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
buttonInsertTime.setOnClickListener(view -> {
editTextGotifyTitle.setFocusable(true);
editTextGotifyTitle.requestFocus();
editTextGotifyTitle.append("{{接收时间}}");
});
Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
buttonInsertDeviceName.setOnClickListener(view -> {
editTextGotifyTitle.setFocusable(true);
editTextGotifyTitle.requestFocus();
editTextGotifyTitle.append("{{设备名称}}");
});
}
@Override
protected void onDestroy() {
Log.d(TAG, "onDestroy");

@ -22,6 +22,7 @@ public class SenderModel {
public static final int TYPE_SMS = 8;
public static final int TYPE_FEISHU = 9;
public static final int TYPE_PUSHPLUS = 10;
public static final int TYPE_GOTIFY = 11;
private Long id;
private String name;
private int status;
@ -61,6 +62,8 @@ public class SenderModel {
return R.mipmap.feishu;
case (TYPE_PUSHPLUS):
return R.mipmap.pushplus;
case (TYPE_GOTIFY):
return R.mipmap.gotify;
case (TYPE_SMS):
default:
return R.mipmap.sms;
@ -89,6 +92,8 @@ public class SenderModel {
return R.mipmap.feishu;
case (TYPE_PUSHPLUS):
return R.mipmap.pushplus;
case (TYPE_GOTIFY):
return R.mipmap.gotify;
case (TYPE_SMS):
default:
return R.mipmap.sms;

@ -0,0 +1,22 @@
package com.idormy.sms.forwarder.model.vo;
import java.io.Serializable;
import lombok.Data;
@Data
public class GotifySettingVo implements Serializable {
private String webServer;
private String title;
private String priority;
public GotifySettingVo() {
}
public GotifySettingVo(String webServer, String title, String priority) {
this.webServer = webServer;
this.title = title;
this.priority = priority;
}
}

@ -0,0 +1,94 @@
package com.idormy.sms.forwarder.sender;
import android.os.Handler;
import android.util.Log;
import androidx.annotation.NonNull;
import com.idormy.sms.forwarder.model.vo.GotifySettingVo;
import com.idormy.sms.forwarder.utils.LogUtil;
import com.idormy.sms.forwarder.utils.SettingUtil;
import java.io.IOException;
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.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@SuppressWarnings({"ResultOfMethodCallIgnored", "rawtypes", "unchecked", "deprecation"})
public class SenderGotifyMsg extends SenderBaseMsg {
static final String TAG = "SenderGotifyMsg";
public static void sendMsg(final long logId, final Handler handError, GotifySettingVo gotifySettingVo, String title, String message) throws Exception {
//具体消息内容
if (message == null || message.isEmpty()) return;
final RequestBody formBody = new FormBody.Builder()
.add("title", title)
.add("message", message)
.add("priority", gotifySettingVo.getPriority())
.build();
final String requestUrl = gotifySettingVo.getWebServer();
Log.i(TAG, "requestUrl:" + requestUrl);
Observable
.create((ObservableEmitter<Object> emitter) -> {
Toast(handError, TAG, "开始请求接口...");
final Request request = new Request.Builder()
.url(requestUrl)
.post(formBody)
.build();
OkHttpClient client = new OkHttpClient();
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 ("200".equals(response.code())) {
LogUtil.updateLog(logId, 2, responseStr);
} else {
LogUtil.updateLog(logId, 0, responseStr);
}
}
});
}).retryWhen((Observable<Throwable> 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);
}
}

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/set_name" />
<EditText
android:id="@+id/editTextGotifyName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="11"
android:inputType="text"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/GotifyWebServer" />
<EditText
android:id="@+id/editTextGotifyWebServer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autofillHints=""
android:ems="14"
android:inputType="textUri"
android:text=""
tools:ignore="LabelFor" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_sms_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="5dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题模板" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/custom_templates_tips"
android:textSize="11sp" />
</LinearLayout>
<EditText
android:id="@+id/editTextGotifyTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:inputType="text"
android:gravity="start|top"
android:minLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_insert_sender"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:background="@color/colorBlueGrey"
android:text="@string/insert_sender"
tools:ignore="ButtonStyle,NestedWeights" />
<Button
android:id="@+id/bt_insert_extra"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:background="@color/colorBlueGrey"
android:text="@string/insert_extra"
tools:ignore="ButtonStyle,NestedWeights" />
<Button
android:id="@+id/bt_insert_time"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:background="@color/colorBlueGrey"
android:text="@string/insert_time"
tools:ignore="ButtonStyle,NestedWeights" />
<Button
android:id="@+id/bt_insert_device_name"
android:layout_width="match_parent"
android:layout_height="25dp"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1"
android:background="@color/colorBlueGrey"
android:text="@string/insert_device_name"
tools:ignore="ButtonStyle,NestedWeights" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="优先级" />
<EditText
android:id="@+id/editTextGotifyPriority"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="14"
android:inputType="number"
android:digits="123456789"
android:maxLength="3"
android:maxLines="1"
android:text="5"
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="horizontal">
<Button
android:id="@+id/buttonGotifyTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:text="@string/test"
tools:ignore="ButtonStyle,NestedWeights" />
<Button
android:id="@+id/buttonGotifyDel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:text="@string/del"
tools:ignore="ButtonStyle,NestedWeights" />
<Button
android:id="@+id/buttonGotifyOk"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/ok"
tools:ignore="ButtonStyle,NestedWeights" />
</LinearLayout>
</LinearLayout>
</ScrollView>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@ -12,5 +12,6 @@
<item>SMS</item>
<item>FeiShu Bot</item>
<item>PushPlus</item>
<item>Gotify</item>
</string-array>
</resources>

@ -101,6 +101,7 @@
<string name="setsmstitle">SMS Settings</string>
<string name="setfeishutitle">FeiShu Bot Settings</string>
<string name="setpushplustitle">PushPlus Settings</string>
<string name="setgotifytitle">Gotify Settings</string>
<string name="test_phone_num">19999999999</string>
<string name="test_content">Test content @</string>
<string name="test_sms">【JD】code 387481, ihelp.jd.com</string>
@ -273,4 +274,5 @@
<string name="agree">Agree</string>
<string name="disagree">Disagree</string>
<string name="privacy_policy_text">SmsForwarder (the "Application/App"), is 100\% free and open source, and is compliled and released basing on repository hosted on GitHub. The App will not collect any of your privacy data!\n\n Version information of the App will be sent in the following situations: \n 1. As startup, version information will be sent to "Umeng +· U-APP Mobile Statistics" for user retention analyze and crash stats;\n 2. Manual update check triggered by user;\n The App collects no any other data!!\n\n The App collects and uses version information only in accordance with the Privacy Policy, and will not collect any other information as an abuse of users\' consent to the Privacy Policy;</string>
<string name="GotifyWebServer"><![CDATA[设置WebServer例如https://push.example.de/message?token=<apptoken>]]></string>
</resources>

@ -12,5 +12,6 @@
<item>其他手机短信</item>
<item>飞书机器人</item>
<item>PushPlus</item>
<item>Gotify</item>
</string-array>
</resources>

@ -101,6 +101,7 @@
<string name="setsmstitle">设置SMS</string>
<string name="setfeishutitle">设置飞书机器人</string>
<string name="setpushplustitle">设置PushPlus</string>
<string name="setgotifytitle">设置Gotify</string>
<string name="test_phone_num">19999999999</string>
<string name="test_content">测试内容(content)@</string>
<string name="test_sms">【京东】验证码为387481切勿将验证码告知他人请在页面中输入完成验证如有问题请点击 ihelp.jd.com 联系京东客服</string>
@ -272,4 +273,5 @@
<string name="agree">同意</string>
<string name="disagree">不同意</string>
<string name="privacy_policy_text">SmsForwarder-短信转发器(下称本软件) 100% 免费开源Github 在线编译发版,绝不会收集您的任何隐私数据! \n\n以下情形会上报本软件版本信息 \n 1、启动本软件时发送版本信息发送到《友盟+·U-App移动统计》用于分析本软件的用户版本留存与软件奔溃统计 \n 2、手动检查更新时发送版本号用于检查新版本 \n除此之外没有任何数据 \n\n本软件会遵循《隐私政策》收集、使用版本信息但不会因为您同意了《隐私政策》而进行强制捆绑式的信息收集。</string>
<string name="GotifyWebServer"><![CDATA[设置WebServer例如https://push.example.de/message?token=<apptoken>]]></string>
</resources>

Loading…
Cancel
Save