From 565795a843ab00ee959be84dcb3903dc892edb8b Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Sat, 11 Feb 2023 16:24:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9ASocket=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=80=9A=E9=81=93=EF=BC=88=E6=94=AF=E6=8C=81MQTT/TCP/?= =?UTF-8?q?UDP=E5=8D=8F=E8=AE=AE=EF=BC=89=20#252?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 3 + app/libs/socket.aar | Bin 0 -> 87683 bytes app/proguard-rules.pro | 2 + .../forwarder/database/entity/LogsDetail.kt | 1 + .../sms/forwarder/database/entity/Sender.kt | 2 + .../database/ext/ConvertersSenderList.kt | 4 +- .../forwarder/entity/setting/SocketSetting.kt | 32 ++ .../sms/forwarder/fragment/SendersFragment.kt | 2 + .../fragment/senders/SocketFragment.kt | 252 ++++++++++ .../idormy/sms/forwarder/utils/CommonUtils.kt | 145 +++--- .../idormy/sms/forwarder/utils/Constants.kt | 8 + .../idormy/sms/forwarder/utils/SendUtils.kt | 6 +- .../sms/forwarder/utils/sender/SocketUtils.kt | 182 ++++++++ app/src/main/res/drawable/icon_socket.webp | Bin 0 -> 1958 bytes .../adapter_logs_card_view_list_item.xml | 96 ++-- .../adapter_rules_card_view_list_item.xml | 2 +- .../main/res/layout/fragment_rules_edit.xml | 2 +- .../res/layout/fragment_senders_socket.xml | 440 ++++++++++++++++++ app/src/main/res/layout/fragment_server.xml | 3 +- app/src/main/res/layout/fragment_settings.xml | 6 +- app/src/main/res/values-en/arrays.xml | 12 + app/src/main/res/values-en/strings.xml | 31 +- app/src/main/res/values/arrays.xml | 12 + app/src/main/res/values/strings.xml | 33 +- 24 files changed, 1134 insertions(+), 142 deletions(-) create mode 100644 app/libs/socket.aar create mode 100644 app/src/main/java/com/idormy/sms/forwarder/entity/setting/SocketSetting.kt create mode 100644 app/src/main/java/com/idormy/sms/forwarder/fragment/senders/SocketFragment.kt create mode 100644 app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt create mode 100644 app/src/main/res/drawable/icon_socket.webp create mode 100644 app/src/main/res/layout/fragment_senders_socket.xml diff --git a/app/build.gradle b/app/build.gradle index ce5890f8..a9ad0df1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -188,6 +188,9 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) //frpc implementation files('libs/frpclib.aar') + //kmnkt是基于Kotlin Multiplatform的跨平台socket通信统一接口。支持Android目标与JVM目标,支持UDP/TCP/MQTT协议使用同一套接口实现 + implementation("org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5") + implementation files('libs/socket.aar') testImplementation deps.junit androidTestImplementation 'androidx.test.ext:junit:1.1.5' diff --git a/app/libs/socket.aar b/app/libs/socket.aar new file mode 100644 index 0000000000000000000000000000000000000000..708c9844993e61f5622e1579b6de34ff07006f18 GIT binary patch literal 87683 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 E1*SnWE&u=k literal 0 HcmV?d00001 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index dc956622..b0c483e2 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -282,6 +282,8 @@ -keep class javax.activation.** { *;} -keep class com.smailnet.emailkit.** { *;} -keep class com.idormy.sms.forwarder.utils.mail.** {*;} +-keep class com.gitee.xuankaicat.kmnkt.** {*;} +-keep class org.eclipse.paho.client.** {*;} -keep public class com.xuexiang.xrouter.routes.**{*;} -keep class * implements com.xuexiang.xrouter.facade.template.ISyringe{*;} diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/entity/LogsDetail.kt b/app/src/main/java/com/idormy/sms/forwarder/database/entity/LogsDetail.kt index 5619c359..4e1b94a1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/entity/LogsDetail.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/entity/LogsDetail.kt @@ -54,6 +54,7 @@ data class LogsDetail( TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner TYPE_FEISHU_APP -> R.drawable.icon_feishu_app TYPE_URL_SCHEME -> R.drawable.icon_url_scheme + TYPE_SOCKET -> R.drawable.icon_socket else -> R.drawable.icon_sms } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt index 4a9a6b26..2627bdaf 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt @@ -38,6 +38,7 @@ data class Sender( TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner TYPE_FEISHU_APP -> R.drawable.icon_feishu_app TYPE_URL_SCHEME -> R.drawable.icon_url_scheme + TYPE_SOCKET -> R.drawable.icon_socket else -> R.drawable.icon_sms } @@ -60,6 +61,7 @@ data class Sender( TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner TYPE_FEISHU_APP -> R.drawable.icon_feishu_app TYPE_URL_SCHEME -> R.drawable.icon_url_scheme + TYPE_SOCKET -> R.drawable.icon_socket else -> R.drawable.icon_sms } diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/ext/ConvertersSenderList.kt b/app/src/main/java/com/idormy/sms/forwarder/database/ext/ConvertersSenderList.kt index cdc09c22..a04eb775 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/ext/ConvertersSenderList.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/ext/ConvertersSenderList.kt @@ -10,7 +10,7 @@ class ConvertersSenderList { @TypeConverter fun stringToObject(value: String): List { - var senderList: MutableList = mutableListOf() + val senderList: MutableList = mutableListOf() value.split(",").map { it.trim() }.forEach { val sender = Core.sender.getOne(it.toLong()) senderList.add(sender) @@ -20,7 +20,7 @@ class ConvertersSenderList { @TypeConverter fun objectToString(list: List): String { - var senderList = ArrayList() + val senderList = ArrayList() list.forEach { senderList += it.id } diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/SocketSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/SocketSetting.kt new file mode 100644 index 00000000..2a719498 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/SocketSetting.kt @@ -0,0 +1,32 @@ +package com.idormy.sms.forwarder.entity.setting + +import com.idormy.sms.forwarder.R +import java.io.Serializable + +data class SocketSetting( + val method: String? = "MQTT", + var address: String = "", //IP地址 + val port: Int = 0, //端口号 + val msgTemplate: String = "", //消息模板 + val secret: String? = "", //签名密钥 + val username: String = "", //用户名 + val password: String = "", //密码 + val inCharset: String = "", //输入编码 + val outCharset: String = "", //输出编码 + val inMessageTopic: String = "", //Mqtt专属,输入信息响应主题,即接收对应主题的消息 + val outMessageTopic: String = "", //Mqtt专属,输出信息响应主题,即发送对应主题的消息 + val uriType: String = "tcp", //Mqtt专属,通信方式 默认为tcp + val path: String = "", //Mqtt专属,通信路径,用于在使用ws进行通信时设置uri,最后的访问结果为"${uriType}://${address}:${port}${path}" + val clientId: String = "", //Mqtt专属,客户端ID,如果为空则为随机值 +) : Serializable { + + fun getMethodCheckId(): Int { + return when (method) { + null, "MQTT" -> R.id.rb_method_mqtt + "TCP" -> R.id.rb_method_tcp + "UDP" -> R.id.rb_method_udp + else -> R.id.rb_method_mqtt + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt index f21c486f..7d7d12f0 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/SendersFragment.kt @@ -110,6 +110,7 @@ class SendersFragment : BaseFragment(), SenderPagingAda TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java TYPE_FEISHU_APP -> FeishuAppFragment::class.java TYPE_URL_SCHEME -> UrlSchemeFragment::class.java + TYPE_SOCKET -> SocketFragment::class.java else -> DingtalkGroupRobotFragment::class.java } ).setNewActivity(true) @@ -136,6 +137,7 @@ class SendersFragment : BaseFragment(), SenderPagingAda TYPE_DINGTALK_INNER_ROBOT -> DingtalkInnerRobotFragment::class.java TYPE_FEISHU_APP -> FeishuAppFragment::class.java TYPE_URL_SCHEME -> UrlSchemeFragment::class.java + TYPE_SOCKET -> SocketFragment::class.java else -> DingtalkGroupRobotFragment::class.java } ).setNewActivity(true) diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/SocketFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/SocketFragment.kt new file mode 100644 index 00000000..d60e54ab --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/senders/SocketFragment.kt @@ -0,0 +1,252 @@ +package com.idormy.sms.forwarder.fragment.senders + +import android.os.Looper +import android.text.TextUtils +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.RadioGroup +import androidx.fragment.app.viewModels +import com.google.gson.Gson +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.core.BaseFragment +import com.idormy.sms.forwarder.database.AppDatabase +import com.idormy.sms.forwarder.database.entity.Sender +import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory +import com.idormy.sms.forwarder.database.viewmodel.SenderViewModel +import com.idormy.sms.forwarder.databinding.FragmentSendersSocketBinding +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.setting.SocketSetting +import com.idormy.sms.forwarder.utils.* +import com.idormy.sms.forwarder.utils.sender.SocketUtils +import com.jeremyliao.liveeventbus.LiveEventBus +import com.xuexiang.xaop.annotation.SingleClick +import com.xuexiang.xpage.annotation.Page +import com.xuexiang.xrouter.annotation.AutoWired +import com.xuexiang.xrouter.launcher.XRouter +import com.xuexiang.xui.utils.CountDownButtonHelper +import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction +import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.util.* + +@Page(name = "Socket") +@Suppress("PrivatePropertyName") +class SocketFragment : BaseFragment(), View.OnClickListener { + + private val TAG: String = SocketFragment::class.java.simpleName + var titleBar: TitleBar? = null + private val viewModel by viewModels { BaseViewModelFactory(context) } + private var mCountDownHelper: CountDownButtonHelper? = null + + @JvmField + @AutoWired(name = KEY_SENDER_ID) + var senderId: Long = 0 + + @JvmField + @AutoWired(name = KEY_SENDER_TYPE) + var senderType: Int = 0 + + @JvmField + @AutoWired(name = KEY_SENDER_CLONE) + var isClone: Boolean = false + + override fun initArgs() { + XRouter.getInstance().inject(this) + } + + override fun viewBindingInflate( + inflater: LayoutInflater, + container: ViewGroup, + ): FragmentSendersSocketBinding { + return FragmentSendersSocketBinding.inflate(inflater, container, false) + } + + override fun initTitle(): TitleBar? { + titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.socket) + return titleBar + } + + /** + * 初始化控件 + */ + override fun initViews() { + //测试按钮增加倒计时,避免重复点击 + mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, SettingUtils.requestTimeout) + mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener { + override fun onCountDown(time: Int) { + binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time) + } + + override fun onFinished() { + binding!!.btnTest.text = getString(R.string.test) + } + }) + + //新增 + if (senderId <= 0) { + titleBar?.setSubTitle(getString(R.string.add_sender)) + binding!!.btnDel.setText(R.string.discard) + return + } + + //编辑 + binding!!.btnDel.setText(R.string.del) + AppDatabase.getInstance(requireContext()).senderDao().get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) {} + + override fun onError(e: Throwable) { + e.printStackTrace() + } + + override fun onSuccess(sender: Sender) { + if (isClone) { + titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name) + binding!!.btnDel.setText(R.string.discard) + } else { + titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name) + } + binding!!.etName.setText(sender.name) + binding!!.sbEnable.isChecked = sender.status == 1 + val settingVo = Gson().fromJson(sender.jsonSetting, SocketSetting::class.java) + Log.d(TAG, settingVo.toString()) + if (settingVo != null) { + val checkedId = settingVo.getMethodCheckId() + binding!!.rgMethod.check(checkedId) + binding!!.etAddress.setText(settingVo.address) + binding!!.etPort.setText(settingVo.port.toString()) + binding!!.etMsgTemplate.setText(settingVo.msgTemplate) + binding!!.etSecret.setText(settingVo.secret) + binding!!.etUsername.setText(settingVo.username) + binding!!.etPassword.setText(settingVo.password) + binding!!.etInCharset.setSelectedItem(settingVo.inCharset) + binding!!.etOutCharset.setSelectedItem(settingVo.outCharset) + binding!!.etInMessageTopic.setText(settingVo.inMessageTopic) + binding!!.etOutMessageTopic.setText(settingVo.outMessageTopic) + binding!!.etUriType.setText(settingVo.uriType) + binding!!.etPath.setText(settingVo.path) + binding!!.etClientId.setText(settingVo.clientId) + binding!!.layoutMqtt.visibility = if (checkedId == R.id.rb_method_mqtt) View.VISIBLE else View.GONE + } + } + }) + } + + override fun initListeners() { + binding!!.btnTest.setOnClickListener(this) + binding!!.btnDel.setOnClickListener(this) + binding!!.btnSave.setOnClickListener(this) + binding!!.rgMethod.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> + binding!!.layoutMqtt.visibility = if (checkedId == R.id.rb_method_mqtt) View.VISIBLE else View.GONE + } + LiveEventBus.get(KEY_SENDER_TEST, String::class.java).observe(this) { mCountDownHelper?.finish() } + } + + @SingleClick + override fun onClick(v: View) { + try { + when (v.id) { + R.id.btn_test -> { + mCountDownHelper?.start() + Thread { + try { + val settingVo = checkSetting() + Log.d(TAG, settingVo.toString()) + val msgInfo = MsgInfo( + "sms", getString(R.string.test_phone_num), getString(R.string.test_sender_sms), Date(), getString(R.string.test_sim_info) + ) + SocketUtils.sendMsg(settingVo, msgInfo) + } catch (e: Exception) { + e.printStackTrace() + if (Looper.myLooper() == null) Looper.prepare() + XToastUtils.error(e.message.toString()) + Looper.loop() + } + LiveEventBus.get(KEY_SENDER_TEST, String::class.java).post("finish") + }.start() + return + } + R.id.btn_del -> { + if (senderId <= 0 || isClone) { + popToBack() + return + } + + MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? -> + viewModel.delete(senderId) + XToastUtils.success(R.string.delete_sender_toast) + popToBack() + }.show() + return + } + R.id.btn_save -> { + val name = binding!!.etName.text.toString().trim() + if (TextUtils.isEmpty(name)) { + throw Exception(getString(R.string.invalid_name)) + } + + val status = if (binding!!.sbEnable.isChecked) 1 else 0 + val settingVo = checkSetting() + if (isClone) senderId = 0 + val senderNew = Sender(senderId, senderType, name, Gson().toJson(settingVo), status) + Log.d(TAG, senderNew.toString()) + + viewModel.insertOrUpdate(senderNew) + XToastUtils.success(R.string.tipSaveSuccess) + popToBack() + return + } + } + } catch (e: Exception) { + XToastUtils.error(e.message.toString()) + e.printStackTrace() + } + } + + private fun checkSetting(): SocketSetting { + val address = binding!!.etAddress.text.toString().trim() + if (CommonUtils.checkIP(address) == "Neither" && !CommonUtils.checkDomain(address)) { + throw Exception(getString(R.string.invalid_ip)) + } + + val port = binding!!.etPort.text.toString().trim() + if (!CommonUtils.checkPort(port)) { + throw Exception(getString(R.string.invalid_port)) + } + + val method = when (binding!!.rgMethod.checkedRadioButtonId) { + R.id.rb_method_tcp -> "TCP" + R.id.rb_method_udp -> "UDP" + else -> "MQTT" + } + + val msgTemplate = binding!!.etMsgTemplate.text.toString().trim() + val secret = binding!!.etSecret.text.toString().trim() + val username = binding!!.etUsername.text.toString().trim() + val password = binding!!.etPassword.text.toString().trim() + val inCharset = binding!!.etInCharset.text.toString().trim() + val outCharset = binding!!.etOutCharset.text.toString().trim() + val inMessageTopic = binding!!.etInMessageTopic.text.toString().trim() + val outMessageTopic = binding!!.etOutMessageTopic.text.toString().trim() + val uriType = binding!!.etUriType.text.toString().trim() + val path = binding!!.etPath.text.toString().trim() + val clientId = binding!!.etClientId.text.toString().trim() + + if (method == "MQTT" && (TextUtils.isEmpty(inMessageTopic) || TextUtils.isEmpty(outMessageTopic))) { + throw Exception(getString(R.string.invalid_mqtt_message_topic)) + } + + return SocketSetting(method, address, port.toInt(), msgTemplate, secret, username, password, inCharset, outCharset, inMessageTopic, outMessageTopic, uriType, path, clientId) + } + + override fun onDestroyView() { + if (mCountDownHelper != null) mCountDownHelper!!.recycle() + super.onDestroyView() + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/CommonUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/CommonUtils.kt index d1959b5e..f53565d6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/CommonUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/CommonUtils.kt @@ -60,49 +60,34 @@ class CommonUtils private constructor() { @Suppress("SameParameterValue", "NAME_SHADOWING") @JvmStatic fun showPrivacyDialog(context: Context, submitListener: SingleButtonCallback?): Dialog { - val dialog = - MaterialDialog.Builder(context).title(R.string.title_reminder).autoDismiss(false) - .cancelable(false) - .positiveText(R.string.lab_agree) - .onPositive { dialog1: MaterialDialog, which: DialogAction? -> - if (submitListener != null) { - submitListener.onClick(dialog1, which!!) - } else { - dialog1.dismiss() - } - } - .negativeText(R.string.lab_disagree).onNegative { dialog, _ -> + val dialog = MaterialDialog.Builder(context).title(R.string.title_reminder).autoDismiss(false).cancelable(false).positiveText(R.string.lab_agree).onPositive { dialog1: MaterialDialog, which: DialogAction? -> + if (submitListener != null) { + submitListener.onClick(dialog1, which!!) + } else { + dialog1.dismiss() + } + }.negativeText(R.string.lab_disagree).onNegative { dialog, _ -> + dialog.dismiss() + DialogLoader.getInstance().showConfirmDialog( + context, ResUtils.getString(R.string.title_reminder), String.format( + ResUtils.getString(R.string.content_privacy_explain_again), ResUtils.getString(R.string.app_name) + ), ResUtils.getString(R.string.lab_look_again), { dialog, _ -> dialog.dismiss() - DialogLoader.getInstance().showConfirmDialog( - context, - ResUtils.getString(R.string.title_reminder), - String.format( - ResUtils.getString(R.string.content_privacy_explain_again), - ResUtils.getString(R.string.app_name) - ), - ResUtils.getString(R.string.lab_look_again), - { dialog, _ -> - dialog.dismiss() - showPrivacyDialog(context, submitListener) - }, - ResUtils.getString(R.string.lab_still_disagree) - ) { dialog, _ -> + showPrivacyDialog(context, submitListener) + }, ResUtils.getString(R.string.lab_still_disagree) + ) { dialog, _ -> + dialog.dismiss() + DialogLoader.getInstance().showConfirmDialog( + context, ResUtils.getString(R.string.content_think_about_it_again), ResUtils.getString(R.string.lab_look_again), { dialog, _ -> dialog.dismiss() - DialogLoader.getInstance().showConfirmDialog( - context, - ResUtils.getString(R.string.content_think_about_it_again), - ResUtils.getString(R.string.lab_look_again), - { dialog, _ -> - dialog.dismiss() - showPrivacyDialog(context, submitListener) - }, - ResUtils.getString(R.string.lab_exit_app) - ) { dialog, _ -> - dialog.dismiss() - XUtil.exitApp() - } - } - }.build() + showPrivacyDialog(context, submitListener) + }, ResUtils.getString(R.string.lab_exit_app) + ) { dialog, _ -> + dialog.dismiss() + XUtil.exitApp() + } + } + }.build() dialog.setContent(getPrivacyContent(context)) //开始响应点击事件 dialog.contentView!!.movementMethod = LinkMovementMethod.getInstance() @@ -114,15 +99,7 @@ class CommonUtils private constructor() { * @return 隐私政策说明 */ private fun getPrivacyContent(context: Context): SpannableStringBuilder { - return SpannableStringBuilder() - .append(" ").append(ResUtils.getString(R.string.privacy_content_1)).append(" ").append(ResUtils.getString(R.string.app_name)).append("!\n") - .append(" ").append(ResUtils.getString(R.string.privacy_content_2)) - .append(" ").append(ResUtils.getString(R.string.privacy_content_3)) - .append(getPrivacyLink(context, PRIVACY_URL)) - .append(ResUtils.getString(R.string.privacy_content_4)) - .append(" ").append(ResUtils.getString(R.string.privacy_content_5)) - .append(getPrivacyLink(context, PRIVACY_URL)) - .append(ResUtils.getString(R.string.privacy_content_6)) + return SpannableStringBuilder().append(" ").append(ResUtils.getString(R.string.privacy_content_1)).append(" ").append(ResUtils.getString(R.string.app_name)).append("!\n").append(" ").append(ResUtils.getString(R.string.privacy_content_2)).append(" ").append(ResUtils.getString(R.string.privacy_content_3)).append(getPrivacyLink(context, PRIVACY_URL)).append(ResUtils.getString(R.string.privacy_content_4)).append(" ").append(ResUtils.getString(R.string.privacy_content_5)).append(getPrivacyLink(context, PRIVACY_URL)).append(ResUtils.getString(R.string.privacy_content_6)) } /** @@ -132,8 +109,7 @@ class CommonUtils private constructor() { @Suppress("SameParameterValue") private fun getPrivacyLink(context: Context, privacyUrl: String): SpannableString { val privacyName = String.format( - ResUtils.getString(R.string.lab_privacy_name), - ResUtils.getString(R.string.app_name) + ResUtils.getString(R.string.lab_privacy_name), ResUtils.getString(R.string.app_name) ) val spannableString = SpannableString(privacyName) spannableString.setSpan(object : ClickableSpan() { @@ -165,15 +141,11 @@ class CommonUtils private constructor() { */ @JvmStatic fun gotoProtocol(fragment: XPageFragment?, isPrivacy: Boolean, isImmersive: Boolean) { - PageOption.to(ServiceProtocolFragment::class.java) - .putString( - ServiceProtocolFragment.KEY_PROTOCOL_TITLE, - if (isPrivacy) ResUtils.getString(R.string.title_privacy_protocol) else ResUtils.getString( - R.string.title_user_protocol - ) + PageOption.to(ServiceProtocolFragment::class.java).putString( + ServiceProtocolFragment.KEY_PROTOCOL_TITLE, if (isPrivacy) ResUtils.getString(R.string.title_privacy_protocol) else ResUtils.getString( + R.string.title_user_protocol ) - .putBoolean(ServiceProtocolFragment.KEY_IS_IMMERSIVE, isImmersive) - .open(fragment!!) + ).putBoolean(ServiceProtocolFragment.KEY_IS_IMMERSIVE, isImmersive).open(fragment!!) } /** @@ -210,13 +182,7 @@ class CommonUtils private constructor() { } val bounds = Rect() view?.getGlobalVisibleRect(bounds) - PreviewBuilder.from(fragment) - .setImgs(ImageInfo.newInstance(url, bounds)) - .setCurrentIndex(0) - .setSingleFling(true) - .setProgressColor(R.color.xui_config_color_main_theme) - .setType(PreviewBuilder.IndicatorType.Number) - .start() + PreviewBuilder.from(fragment).setImgs(ImageInfo.newInstance(url, bounds)).setCurrentIndex(0).setSingleFling(true).setProgressColor(R.color.xui_config_color_main_theme).setType(PreviewBuilder.IndicatorType.Number).start() } /** @@ -228,11 +194,7 @@ class CommonUtils private constructor() { */ @JvmStatic fun previewMarkdown(fragment: XPageFragment?, title: String, url: String, isImmersive: Boolean) { - PageOption.to(MarkdownFragment::class.java) - .putString(MarkdownFragment.KEY_MD_TITLE, title) - .putString(MarkdownFragment.KEY_MD_URL, url) - .putBoolean(MarkdownFragment.KEY_IS_IMMERSIVE, isImmersive) - .open(fragment!!) + PageOption.to(MarkdownFragment::class.java).putString(MarkdownFragment.KEY_MD_TITLE, title).putString(MarkdownFragment.KEY_MD_URL, url).putBoolean(MarkdownFragment.KEY_IS_IMMERSIVE, isImmersive).open(fragment!!) } //是否合法的url @@ -243,7 +205,7 @@ class CommonUtils private constructor() { //是否合法的url fun checkUrl(urls: String?, emptyResult: Boolean): Boolean { if (TextUtils.isEmpty(urls)) return emptyResult - val regex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\\[\\]]*[-a-zA-Z0-9+&@#/%=~_|\\[\\]]" + val regex = "^(https?|ftp|file)://[-a-zA-Z\\d+&@#/%?=~_|!:,.;\\[\\]]*[-a-zA-Z\\d+&@#/%=~_|\\[\\]]" val pat = Pattern.compile(regex) val mat = pat.matcher(urls?.trim() ?: "") return mat.matches() @@ -257,12 +219,41 @@ class CommonUtils private constructor() { //是否合法的URL Scheme fun checkUrlScheme(urls: String?, emptyResult: Boolean): Boolean { if (TextUtils.isEmpty(urls)) return emptyResult - val regex = "^[a-zA-Z0-9]+://[-a-zA-Z0-9+&@#/%?=~_|!:,.;\\[\\]]*[-a-zA-Z0-9+&@#/%=~_|\\[\\]]" + val regex = "^[a-zA-Z\\d]+://[-a-zA-Z\\d+&@#/%?=~_|!:,.;\\[\\]]*[-a-zA-Z\\d+&@#/%=~_|\\[\\]]" val pat = Pattern.compile(regex) val mat = pat.matcher(urls?.trim() ?: "") return mat.matches() } + //是否合法的IP地址 + fun checkIP(IP: String): String { + if (TextUtils.isEmpty(IP)) return "Neither" + + if (IP.contains(".")) { + val chunkIPv4 = "([\\d]|[1-9][\\d]|1[\\d][\\d]|2[0-4][\\d]|25[0-5])" + val pattenIPv4 = Pattern.compile("^($chunkIPv4\\.){3}$chunkIPv4$") + return if (pattenIPv4.matcher(IP).matches()) "IPv4" else "Neither" + } else if (IP.contains(":")) { + val chunkIPv6 = "([\\da-fA-F]{1,4})" + val pattenIPv6 = Pattern.compile("^($chunkIPv6\\:){7}$chunkIPv6$") + return if (pattenIPv6.matcher(IP).matches()) "IPv6" else "Neither" + } + return "Neither" + } + + //是否合法的域名 + fun checkDomain(domain: String): Boolean { + val pattenDomain = Pattern.compile("^(?=^.{3,255}$)(?:(?:(?:[a-zA-Z\\d]|[a-zA-Z\\d][a-zA-Z\\d\\-]*[a-zA-Z\\d])\\.){1,126}(?:[A-Za-z\\d]|[A-Za-z\\d][A-Za-z\\d\\-]*[A-Za-z\\d]))$") + return pattenDomain.matcher(domain).matches() + } + + //是否合法的端口号 + fun checkPort(port: String): Boolean { + if (TextUtils.isEmpty(port)) return false + val pattenPort = Pattern.compile("^((6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])|[0-5]?\\d{0,4})$") + return pattenPort.matcher(port).matches() + } + //是否启用通知监听服务 fun isNotificationListenerServiceEnabled(context: Context): Boolean { val packageNames = NotificationManagerCompat.getEnabledListenerPackages(context) @@ -273,12 +264,10 @@ class CommonUtils private constructor() { fun toggleNotificationListenerService(context: Context) { val pm = context.packageManager pm.setComponentEnabledSetting( - ComponentName(context.applicationContext, NotifyService::class.java), - PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP + ComponentName(context.applicationContext, NotifyService::class.java), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP ) pm.setComponentEnabledSetting( - ComponentName(context.applicationContext, NotifyService::class.java), - PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP + ComponentName(context.applicationContext, NotifyService::class.java), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP ) } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt index 5aa1dcef..649358d1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt @@ -179,6 +179,7 @@ const val TYPE_GOTIFY = 11 const val TYPE_DINGTALK_INNER_ROBOT = 12 const val TYPE_FEISHU_APP = 13 const val TYPE_URL_SCHEME = 14 +const val TYPE_SOCKET = 15 var SENDER_FRAGMENT_LIST = listOf( PageInfo( getString(R.string.dingtalk_robot), @@ -285,6 +286,13 @@ var SENDER_FRAGMENT_LIST = listOf( CoreAnim.slide, R.drawable.icon_url_scheme ), + PageInfo( + getString(R.string.socket), + "com.idormy.sms.forwarder.fragment.senders.SocketFragment", + "{\"\":\"\"}", + CoreAnim.slide, + R.drawable.icon_socket + ), ) //前台服务 diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt index 5e16311c..25ad525e 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SendUtils.kt @@ -54,7 +54,7 @@ object SendUtils { } } - var rule = item.rule + val rule = item.rule rule.senderLogic = SENDER_LOGIC_RETRY sendMsgSender(msgInfo, rule, senderIndex, logId, item.msg.id) } @@ -124,6 +124,10 @@ object SendUtils { val settingVo = Gson().fromJson(sender.jsonSetting, UrlSchemeSetting::class.java) UrlSchemeUtils.sendMsg(settingVo, msgInfo, rule, senderIndex, logId, msgId) } + TYPE_SOCKET -> { + val settingVo = Gson().fromJson(sender.jsonSetting, SocketSetting::class.java) + SocketUtils.sendMsg(settingVo, msgInfo, rule, senderIndex, logId, msgId) + } else -> { updateLogs(logId, 0, "未知发送通道") } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt new file mode 100644 index 00000000..26bb5ea0 --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt @@ -0,0 +1,182 @@ +package com.idormy.sms.forwarder.utils.sender + +import android.annotation.SuppressLint +import android.text.TextUtils +import android.util.Base64 +import com.gitee.xuankaicat.kmnkt.socket.MqttQuality +import com.gitee.xuankaicat.kmnkt.socket.dsl.mqtt +import com.gitee.xuankaicat.kmnkt.socket.dsl.tcp +import com.gitee.xuankaicat.kmnkt.socket.dsl.udp +import com.gitee.xuankaicat.kmnkt.socket.open +import com.gitee.xuankaicat.kmnkt.socket.utils.Charset +import com.google.gson.Gson +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.setting.SocketSetting +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.xuexiang.xutil.app.AppUtils +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.text.SimpleDateFormat +import java.util.* +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec + +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") +class SocketUtils { + companion object { + + private val TAG: String = SocketUtils::class.java.simpleName + + fun sendMsg( + setting: SocketSetting, msgInfo: MsgInfo, rule: Rule? = null, senderIndex: Int = 0, logId: Long = 0L, msgId: Long = 0L + ) { + val from: String = msgInfo.from + val content: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate) + } + + val timestamp = System.currentTimeMillis() + val orgContent: String = msgInfo.content + val deviceMark: String = SettingUtils.extraDeviceMark + val appVersion: String = AppUtils.getAppVersionName() + val simInfo: String = msgInfo.simInfo + @SuppressLint("SimpleDateFormat") val receiveTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date()) //smsVo.getDate() + var sign = "" + if (!TextUtils.isEmpty(setting.secret)) { + val stringToSign = "$timestamp\n" + setting.secret + val mac = Mac.getInstance("HmacSHA256") + mac.init(SecretKeySpec(setting.secret?.toByteArray(StandardCharsets.UTF_8), "HmacSHA256")) + val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8)) + sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8") + } + + var message = if (TextUtils.isEmpty(setting.msgTemplate)) "{\"msg\": \"[msg]\"}" else setting.msgTemplate + message = if (message.startsWith("{")) { + message.replace("[from]", from).replace("[content]", escapeJson(content)).replace("[msg]", escapeJson(content)).replace("[org_content]", escapeJson(orgContent)).replace("[device_mark]", escapeJson(deviceMark)).replace("[app_version]", appVersion).replace("[title]", escapeJson(simInfo)).replace("[card_slot]", escapeJson(simInfo)).replace("[receive_time]", receiveTime).replace("[timestamp]", timestamp.toString()).replace("[sign]", sign) + } else { + message.replace("[from]", URLEncoder.encode(from, "UTF-8")).replace("[content]", URLEncoder.encode(content, "UTF-8")).replace("[msg]", URLEncoder.encode(content, "UTF-8")).replace("[org_content]", URLEncoder.encode(orgContent, "UTF-8")).replace("[device_mark]", URLEncoder.encode(deviceMark, "UTF-8")).replace("[app_version]", URLEncoder.encode(appVersion, "UTF-8")).replace("[title]", URLEncoder.encode(simInfo, "UTF-8")).replace("[card_slot]", URLEncoder.encode(simInfo, "UTF-8")).replace("[receive_time]", URLEncoder.encode(receiveTime, "UTF-8")).replace("\n", "%0A").replace("[timestamp]", timestamp.toString()).replace("[sign]", sign) + } + + if (setting.method == "TCP" || setting.method == "UDP") { + var isReceived = false + var isConnected = false + val socket = if (setting.method == "TCP") { + tcp { + address = setting.address//设置ip地址 + port = setting.port//设置端口号 + if (!TextUtils.isEmpty(setting.inCharset)) inCharset = Charset.forName(setting.inCharset)//设置输入编码 + if (!TextUtils.isEmpty(setting.outCharset)) outCharset = Charset.forName(setting.outCharset)//设置输出编码 + } + } else { + udp { + address = setting.address//设置ip地址 + port = setting.port//设置端口号 + if (!TextUtils.isEmpty(setting.inCharset)) inCharset = Charset.forName(setting.inCharset)//设置输入编码 + if (!TextUtils.isEmpty(setting.outCharset)) outCharset = Charset.forName(setting.outCharset)//设置输出编码 + } + } + + socket.open { + success { + //开启连接成功时执行 + isConnected = true + SendUtils.updateLogs(logId, 1, "TCP连接成功") + socket.send(message) + socket.startReceive { str, data -> + isReceived = true + android.util.Log.d(TAG, "str=$str,data=$data") + SendUtils.updateLogs(logId, 2, "收到订阅消息:str=$str,data=$data") + SendUtils.senderLogic(2, msgInfo, rule, senderIndex, msgId) + return@startReceive false + } + } + failure { + //开启连接失败时执行 + val status = 0 + SendUtils.updateLogs(logId, status, "TCP连接失败") + SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId) + return@failure false//是否继续尝试连接 + } + loss { + //失去连接时执行 + return@loss false//是否尝试重连 + } + } + + //延时5秒关闭连接 + if (isConnected) { + Thread.sleep(5000) + socket.stopReceive() + socket.close() + if (!isReceived) { + SendUtils.updateLogs(logId, 0, "未收到订阅消息") + SendUtils.senderLogic(0, msgInfo, rule, senderIndex, msgId) + } + } + return + + } else if (setting.method == "MQTT") { + val mqtt = mqtt { + address = setting.address//设置ip地址 + port = setting.port//设置端口号 + if (!TextUtils.isEmpty(setting.inCharset)) inCharset = Charset.forName(setting.inCharset)//设置输入编码 + if (!TextUtils.isEmpty(setting.outCharset)) outCharset = Charset.forName(setting.outCharset)//设置输出编码 + if (!TextUtils.isEmpty(setting.username)) username = setting.username + if (!TextUtils.isEmpty(setting.password)) password = setting.password + if (!TextUtils.isEmpty(setting.inMessageTopic)) inMessageTopic = setting.inMessageTopic + if (!TextUtils.isEmpty(setting.outMessageTopic)) outMessageTopic = setting.outMessageTopic + //自定义配置 + qos = MqttQuality.ExactlyOnce // 服务质量 详见MqttQuality + if (!TextUtils.isEmpty(setting.uriType)) uriType = setting.uriType //通信方式 默认为tcp + if (!TextUtils.isEmpty(setting.clientId)) clientId = setting.clientId //客户端ID,如果为空则为随机值 + timeOut = 10 //设置超时时间 + cleanSession = true //断开连接后是否清楚缓存,如果清除缓存则在重连后需要手动恢复订阅。 + keepAliveInterval = 20 //检测连接是否中断的间隔 + //行为配置 + threadLock = false //是否启用线程同步锁 默认false + } + + mqtt.open { + success { + //开启连接成功时执行 + SendUtils.updateLogs(logId, 1, "MQTT连接成功") + // 订阅并发布后等待至拿到响应消息并赋值给result + // 如果超过10秒没有收到消息则将result设为"消息响应超时",并取消订阅topic + val response = mqtt.sendAndReceiveSync(setting.outMessageTopic, setting.inMessageTopic, message, 10000L) ?: "消息响应超时" + mqtt.close() + + val status = if (response == "消息响应超时") 0 else 2 + SendUtils.updateLogs(logId, status, "收到订阅消息:$response") + SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId) + return@success + } + failure { + //开启连接失败时执行 + val status = 0 + SendUtils.updateLogs(logId, status, "MQTT连接失败") + SendUtils.senderLogic(status, msgInfo, rule, senderIndex, msgId) + return@failure false//是否继续尝试连接 + } + loss { + //失去连接时执行 + return@loss false//是否尝试重连 + } + } + + } + + } + + //JSON需要转义的字符 + private fun escapeJson(str: String?): String { + if (str == null) return "null" + val jsonStr: String = Gson().toJson(str) + return if (jsonStr.length >= 2) jsonStr.substring(1, jsonStr.length - 1) else jsonStr + } + + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/icon_socket.webp b/app/src/main/res/drawable/icon_socket.webp new file mode 100644 index 0000000000000000000000000000000000000000..1f4f0462d0e574f164fe58faae49fbe21bb97035 GIT binary patch literal 1958 zcmV;X2U+-1Nk&GV2LJ$9MM6+kP&il$0000G0001w0055w06|PpNb~^!01Y3*xNRFr zBiVE8J{Q}6xl=<#{ht8*rIuvlNg5vdWK!b+&Y6ZIREF;EpoU{ySWgIX z7<@lmyK>MuG<{0bubzMOmd_8)J;0}Iy7t~Mc*` zpTCZ(ha%FUYCU`LF2o$HTK7?HK`~oZ>*1|cDuYkg5PK+SD;~S>#K#QDUq*2+y{%9` z)7ArUWpOyNxJcEjP;l4xEJANg4_SsWyNr5QR-NRU|6I z|NsC0|NsC0g2)n48AP*oaVqDPW5Mkbiy|%$x;fm(nZw1I+19iA;L`hxDDB9ukU{3& zoIVsoL1Jh2!_LI|kXmc^Zig6(5xcm%f5#w)`km3qJHbE}Ktcz1kM92%GDxXvznr?Y zA4McFcklS&e%m3VQjFcv$7j#(+ul;cv09lOA3J&MV+hQXtm*^-4JX&%dg{cM zjh1)FDvK670n1AfP49Q@VC)C)nMr2RU9 zG(YJ)i6In}lpv_l2*QyVQbE{!YSZx>J62FQAcO?~0FWU7odGJ40FVGakw%zgR!rb|~~!{Qz1KmSK!PUM9q-q)4x22oZW6FVnc7$EKk! z5^th`5#ZY?q2yG6fZ7U5gSrl`ku;VNCOA50<|Q-u@$;=-us zsabDw0{+8WIAJFd+o-|hi>qHIFk&>8+r}O$?UjnsFS(-xU3}DxDU*vdT6qrgVqaWGp>KMK^_>~I*!zyJXL z`}V8<@qInE&-Dz-z8GHrOUMLap6hSQTlLzKF4&FGqes^zoci(nTc7o`Q%>vpo<1`# z(Tpa-mCE(G|7P%i{H}n_u=k@XGd;=Q>K}Hh7o>Q9%e>}3n$2S=a4LR zCTSX1^?CmmA>t_i<)tq<`1Un?C-3gjnqJRZsmP zKUbFrT%2>7T=W1;jrfU+677E*X1rbxsUunkg1io5QAaYFj@csfGC>bT!)RF8zrVfx zedUPmvRkIl1JIZ&0|8OCsWM3}w%Ym^aH|)!R$T{6PNf0A!*I)3T;m{8Py}qDcY8c# zN%VUOt^|9zrQ-dC|14Nw&^)CAhUGW;Ip4-jmu|&qXoSL2q`BhuF+iPVanGsa=^rC! z&H_JwAKcr%LLtjXu$CcS-T4w`1tAFgBn z$DK*ytmP2IpVt$jcAP30Mbn<$GKhE`pBG`2VTwIF2j<<2KjME_SqEEJo?ZHw#Hjhb zrY{+Q%nA5#xoiAXttHoOhA@#Y3aL#Kwu@f(@23f8)#eM6GKW8aCkA4I6Iawx;`vnc z{k8*cMK}H};X$bY2w@O&Qwq)Jt|J=#SU%Y(f2U;2a@V#4({I;fJ?~#tqU=)~cM6`1 zGxVw?15hLGt>L(3Yhs=pj*>QTWk)UI*r|~KfOpbL5ylk77L9E0hf&!DhD7+CY(XEy z9<$&}PvKtl;4`4~e*N$MpjX1r?)um|ANT=x*5MFGY#23q|D6C0C%>(hSa2Y+~- z11hLAWuJihT>`Fpd=ZR6d|49lO(SCM|>+t;Plz6IPf9-v+ zU0fa%SvN~7^qt(NNXhmtdHu>SESMK?A3RLCT_&aF=JHGNaETnm*h3TRNd(K8e*kRcz$52b=7lB0@jN1xflsIg zm5Bn%o3_O1;%TOdEgr+iKcm1_z32+*u2fRU@H1;)v%KP5<^d>@hn?yAQ54d({f1|K zaU#EtKmp(V?LR{SytzGBdri^$B{CHYBTKV2ipi9}4Bt7tp)XLnbG=Raw{^q2mO>(z zyZHsEv?w69PpNpI%*=UHaFj=a3Wkb#!$m~x;=4N3$M6C9Ez!b{ZlyK s#!M$EHqfAJh$E7v?tb&Tv~v&vo{MfVfpd}?9;om&cD33Pmm~lH0JycmI{*Lx literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/adapter_logs_card_view_list_item.xml b/app/src/main/res/layout/adapter_logs_card_view_list_item.xml index bf80a7e2..8f7ac846 100644 --- a/app/src/main/res/layout/adapter_logs_card_view_list_item.xml +++ b/app/src/main/res/layout/adapter_logs_card_view_list_item.xml @@ -16,70 +16,62 @@ + android:orientation="vertical" + tools:ignore="DisableBaselineAlignment"> + android:gravity="center_vertical" + android:orientation="horizontal"> - - - - - - - - - + android:layout_weight="1" /> - - + android:layout_marginStart="5dp" /> - + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_rules_card_view_list_item.xml b/app/src/main/res/layout/adapter_rules_card_view_list_item.xml index 594d0162..3073d93c 100644 --- a/app/src/main/res/layout/adapter_rules_card_view_list_item.xml +++ b/app/src/main/res/layout/adapter_rules_card_view_list_item.xml @@ -65,7 +65,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="5dp" - android:orientation="horizontal"> + android:orientation="horizontal" /> diff --git a/app/src/main/res/layout/fragment_rules_edit.xml b/app/src/main/res/layout/fragment_rules_edit.xml index 7b89778a..7a2eb7a1 100644 --- a/app/src/main/res/layout/fragment_rules_edit.xml +++ b/app/src/main/res/layout/fragment_rules_edit.xml @@ -59,7 +59,7 @@ android:id="@+id/layout_Senders" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> + android:orientation="vertical" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_server.xml b/app/src/main/res/layout/fragment_server.xml index 772bcf43..b9ed264d 100644 --- a/app/src/main/res/layout/fragment_server.xml +++ b/app/src/main/res/layout/fragment_server.xml @@ -664,7 +664,8 @@ + android:layout_height="wrap_content" + tools:ignore="TooManyViews"> + android:visibility="gone" + tools:ignore="RtlSymmetry"> Beagle + + UTF-8 + US-ASCII + ISO-8859-1 + UTF-16 + UTF-16BE + UTF-16LE + UTF-32 + UTF-32LE + UTF-32BE + + \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 7a6eee8d..4633e788 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -398,6 +398,9 @@ GET PUT PATCH + UDP + TCP + MQTT Local IP: Instructions: \n[Note] The APP version of the sender and receiver must be the same!\n1. Please keep the SOURCE and DESTINATION phones in the same Wi-Fi network, and do not turn on isolation. \n2. Tap "Send" on SOURCE mobile phone, and get "server IP" \n3. After filling in "Server IP" on DESTINATION phone, tap "Receive". \n [NOTE:] sender(s), forwarding rule(s) and log(s) will be overwritten after cloning! @@ -410,8 +413,12 @@ Old Phone New Phone Server IP: + Host: + Port: . - Please enter a valid IP address + Please enter a valid IP or domain + Please enter a valid message topic + Please enter a valid port The server is started successfully The server has been stopped This mobile phone is the SOURCE and cannot receive files. @@ -467,6 +474,18 @@ Proxy Authenticator Username Password + In Charset + Out Charset + In Message Topic + Receive messages on the corresponding topic + Out Message Topic + Send a message on the corresponding topic + Uri Type + Optional, default is tcp + Path + Used to set the uri when communicating using ws + Client Id + Random value if empty Privacy Policy Agree Refuse @@ -706,10 +725,18 @@ URL Scheme Example:myapp://api/add?&type=0&msg=[msg] + Socket + Example:myapp://api/add?&type=0&msg=[msg] + 服务地址 + IP 或 域名 + 端口 + 取值范围:1-65535 + Webhook Server For example: https://a.b.com/msg?token=xyz Params - For example: payload=%7B%22text%22%3A%22[msg]%22%7D [msg] will be replaced with SMS content.\nJson format is supported, for example: {\"text\":\"[msg]\"}.\nNote: msg is automatically UTF-8 encoded except in JSON format + Msg Template + For example: payload=%7B%22text%22%3A%22[msg]%22%7D [msg] will be replaced with SMS content.\nJson format is supported, for example: {\"text\":\"[msg]\"}.\nNote: msg is automatically URLEncoder except in JSON format Secret: If it is empty, the sign will not be calculated Headers Key diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 64a0cf0d..0d598342 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -143,4 +143,16 @@ Beagle + + UTF-8 + US-ASCII + ISO-8859-1 + UTF-16 + UTF-16BE + UTF-16LE + UTF-32 + UTF-32LE + UTF-32BE + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3dd75dd7..c823ff35 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -399,6 +399,9 @@ GET PUT PATCH + UDP + TCP + MQTT 本机IP: 严正声明:\n该功能仅限个人新旧手机切换使用,用于非法用途后果自负!\n\n操作说明:\n1.新旧手机连接同一个WiFi网络(禁用AP隔离),如需穿透内网请先配置Frpc\n2.【二选一】旧手机点【推送】按钮,将本机的配置推送到服务端\n3.【二选一】新手机点【拉取】按钮,将拉取服务端的配置到本机\n\n注意事项:\n1.客户端与服务端的APP版本必须一致,才能克隆!\n2.导入成功后,发送通道、转发规则将完全被覆盖,清空历史记录!\n3.主动请求、保活措施、个性设置不在克隆范围 @@ -411,8 +414,12 @@ 我是旧手机 我是新手机 服务端IP: + 主机: + 端口: . - 请输入合法的IP地址 + 请输入合法的IP或域名 + 请输入合法的输入/输出信息主题 + 请输入合法的端口号 服务端已启动 服务端已停止 本手机是发送端,不可接收文件,请先停止服务端! @@ -468,6 +475,18 @@ 代理身份验证 用户 密码 + 输入编码 + 输出编码 + 输入消息主题 + 接收对应主题的消息 + 输出消息主题 + 发送对应主题的消息 + 通信方式 + 可选,默认为tcp + 通信路径 + 用于在使用ws进行通信时设置uri + 客户端ID + 如果为空则为随机值 隐私政策 同意 拒绝 @@ -707,10 +726,18 @@ URL Scheme 示例:myapp://api/add?&type=0&msg=[msg] + Socket + 示例:myapp://api/add?&type=0&msg=[msg] + 服务地址 + IP 或 域名 + 端口 + 取值范围:1-65535 + Webhook Server 例如:https://a.b.com/msg?token=xyz - Params - 例如:payload=%7B%22text%22%3A%22[msg]%22%7D [msg]将被替换成短信内容。\n支持Json格式,例如:{\"text\":\"[msg]\"}。\n注意:除JSON格式外,msg会自动进行UTF-8编码 + 消息模板 + Params + 例如:payload=%7B%22text%22%3A%22[msg]%22%7D [msg]将被替换成短信内容。\n支持Json格式,例如:{\"text\":\"[msg]\"}。\n注意:除JSON格式外,msg会自动进行URLEncoder Secret:置空则不计算sign Headers Key