mirror of
https://gitea.winboll.cc/Studio/WinBoLL.git
synced 2026-08-14 13:37:11 +08:00
合并模块APPBase 同步最新时间标签appbase-v15.21.4
This commit is contained in:
+11
-1
@@ -44,10 +44,20 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE.md'
|
||||
exclude 'META-INF/LICENSE.txt'
|
||||
exclude 'META-INF/NOTICE.md'
|
||||
exclude 'META-INF/NOTICE.txt'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':libappbase')
|
||||
|
||||
|
||||
// JavaMail SMTP (Android兼容版)
|
||||
api 'com.sun.mail:android-mail:1.6.7'
|
||||
api 'com.sun.mail:android-activation:1.6.7'
|
||||
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Tue Jul 21 14:10:49 HKT 2026
|
||||
stageCount=4
|
||||
#Thu Jul 23 19:07:39 HKT 2026
|
||||
stageCount=5
|
||||
libraryProject=libappbase
|
||||
baseVersion=15.21
|
||||
publishVersion=15.21.3
|
||||
publishVersion=15.21.4
|
||||
buildCount=0
|
||||
baseBetaVersion=15.21.4
|
||||
baseBetaVersion=15.21.5
|
||||
|
||||
Vendored
+4
@@ -73,6 +73,10 @@
|
||||
-dontwarn java.util.function.**
|
||||
|
||||
# ============================== 第三方框架规则 ==============================
|
||||
# JavaMail(libaes SMTPConfigView依赖)
|
||||
-keep class javax.mail.** { *; }
|
||||
-dontwarn javax.mail.**
|
||||
|
||||
# Retrofit + OkHttp
|
||||
-keep class retrofit2.** { *; }
|
||||
-keep interface retrofit2.** { *; }
|
||||
|
||||
@@ -2,7 +2,9 @@ package cc.winboll.studio.appbase;
|
||||
|
||||
import cc.winboll.studio.libappbase.CrashActivity;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.libappbase.utils.APPMSGMailUtils;
|
||||
import cc.winboll.studio.libappbase.utils.CrashHandleNotifyUtils;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
@@ -18,6 +20,9 @@ public class App extends GlobalApplication {
|
||||
/** 当前应用类的日志 TAG(用于调试输出,标识日志来源) */
|
||||
public static final String TAG = "App";
|
||||
|
||||
/** SMTP配置 SharedPreferences 名称 */
|
||||
private static final String PREF_NAME = "smtp_config";
|
||||
|
||||
/**
|
||||
* 应用创建时回调(全局初始化入口)
|
||||
* 在应用进程启动时执行,仅调用一次,用于初始化全局工具类、第三方库等
|
||||
@@ -26,15 +31,26 @@ public class App extends GlobalApplication {
|
||||
public void onCreate() {
|
||||
try {
|
||||
super.onCreate();
|
||||
|
||||
|
||||
// 初始化 Toast 工具类(传入应用全局上下文,确保 Toast 可在任意地方调用)
|
||||
ToastUtils.init(getApplicationContext());
|
||||
|
||||
// 调试异常捕获
|
||||
final String errorMsg = "初始化异常捕获调试信息,这个是调试异常捕获的测试数据。";
|
||||
LogUtils.e(TAG, errorMsg);
|
||||
throw new IllegalArgumentException(errorMsg);
|
||||
|
||||
} catch (Throwable e) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
e.printStackTrace(pw);
|
||||
pw.close();
|
||||
String stackTraceStr = sw.toString();
|
||||
|
||||
// 发送异常信息邮箱。
|
||||
sendExceptionMail(stackTraceStr);
|
||||
|
||||
// 前台通知栏提醒。
|
||||
CrashHandleNotifyUtils.handleUncaughtException(
|
||||
this,
|
||||
getPackageName(),
|
||||
@@ -44,6 +60,17 @@ public class App extends GlobalApplication {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送异常报告邮件
|
||||
* 读取SMTP配置,若配置完整则在子线程发送异常堆栈邮件
|
||||
* @param stackTraceStr 异常堆栈信息
|
||||
*/
|
||||
private void sendExceptionMail(final String stackTraceStr) {
|
||||
String subject = "Exception Report - " + getPackageName();
|
||||
String recipients = APPMSGMailUtils.getRecipient(this);
|
||||
APPMSGMailUtils.sendMail(this, subject, stackTraceStr, recipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用终止时回调(资源释放入口)
|
||||
* 仅在模拟环境(如 Android Studio 模拟器)中可靠触发,真机上可能因系统回收进程不执行
|
||||
@@ -56,4 +83,3 @@ public class App extends GlobalApplication {
|
||||
ToastUtils.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-139
@@ -1,162 +1,27 @@
|
||||
package cc.winboll.studio.appbase.develop;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.appbase.R;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.utils.SMTPUtils;
|
||||
import cc.winboll.studio.libappbase.views.SMTPConfigView;
|
||||
|
||||
/**
|
||||
* @Author 豆包&BigPickle&MiMo&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/07/21 12:44
|
||||
* @Describe 应用异常信息邮件接收账号设置
|
||||
* 配置SMTP服务器参数,用于通过邮件发送异常报告
|
||||
* 使用libaes的SMTPConfigView控件配置SMTP服务器参数
|
||||
*/
|
||||
public class APPExcetionMailSettingsActivity extends Activity {
|
||||
|
||||
public static final String TAG = "APPExcetionMailSettingsActivity";
|
||||
|
||||
private static final String PREF_NAME = "smtp_config";
|
||||
private static final String KEY_SMTP_SERVER = "smtp_server";
|
||||
private static final String KEY_SMTP_PORT = "smtp_port";
|
||||
private static final String KEY_SENDER_EMAIL = "sender_email";
|
||||
private static final String KEY_AUTH_CODE = "auth_code";
|
||||
private static final String KEY_RECIPIENT_EMAIL = "recipient_email";
|
||||
|
||||
private EditText mEtSmtpServer;
|
||||
private EditText mEtSmtpPort;
|
||||
private EditText mEtSenderEmail;
|
||||
private EditText mEtAuthCode;
|
||||
private EditText mEtRecipientEmail;
|
||||
private SMTPConfigView mSMTPConfigView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_appexcetionmailsettings);
|
||||
|
||||
mEtSmtpServer = (EditText) findViewById(R.id.et_smtp_server);
|
||||
mEtSmtpPort = (EditText) findViewById(R.id.et_smtp_port);
|
||||
mEtSenderEmail = (EditText) findViewById(R.id.et_sender_email);
|
||||
mEtAuthCode = (EditText) findViewById(R.id.et_auth_code);
|
||||
mEtRecipientEmail = (EditText) findViewById(R.id.et_recipient_email);
|
||||
|
||||
loadConfig();
|
||||
|
||||
Button btnSave = (Button) findViewById(R.id.btn_save);
|
||||
btnSave.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
Button btnTest = (Button) findViewById(R.id.btn_test);
|
||||
btnTest.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
testSendMail();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
SharedPreferences sp = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
String server = sp.getString(KEY_SMTP_SERVER, "smtp.qq.com");
|
||||
String port = sp.getString(KEY_SMTP_PORT, "465");
|
||||
String sender = sp.getString(KEY_SENDER_EMAIL, "");
|
||||
String auth = sp.getString(KEY_AUTH_CODE, "");
|
||||
String recipient = sp.getString(KEY_RECIPIENT_EMAIL, "");
|
||||
|
||||
mEtSmtpServer.setText(server);
|
||||
mEtSmtpPort.setText(port);
|
||||
mEtSenderEmail.setText(sender);
|
||||
mEtAuthCode.setText(auth);
|
||||
mEtRecipientEmail.setText(recipient);
|
||||
}
|
||||
|
||||
private void saveConfig() {
|
||||
String server = mEtSmtpServer.getText().toString().trim();
|
||||
String port = mEtSmtpPort.getText().toString().trim();
|
||||
String sender = mEtSenderEmail.getText().toString().trim();
|
||||
String auth = mEtAuthCode.getText().toString().trim();
|
||||
String recipient = mEtRecipientEmail.getText().toString().trim();
|
||||
|
||||
SharedPreferences.Editor editor = getSharedPreferences(PREF_NAME, MODE_PRIVATE).edit();
|
||||
editor.putString(KEY_SMTP_SERVER, server);
|
||||
editor.putString(KEY_SMTP_PORT, port);
|
||||
editor.putString(KEY_SENDER_EMAIL, sender);
|
||||
editor.putString(KEY_AUTH_CODE, auth);
|
||||
editor.putString(KEY_RECIPIENT_EMAIL, recipient);
|
||||
editor.apply();
|
||||
|
||||
Toast.makeText(this, "设置已保存", Toast.LENGTH_SHORT).show();
|
||||
LogUtils.d(TAG, "saveConfig success, server=" + server + ", port=" + port + ", sender=" + sender);
|
||||
}
|
||||
|
||||
private void testSendMail() {
|
||||
String server = mEtSmtpServer.getText().toString().trim();
|
||||
String portStr = mEtSmtpPort.getText().toString().trim();
|
||||
String sender = mEtSenderEmail.getText().toString().trim();
|
||||
String auth = mEtAuthCode.getText().toString().trim();
|
||||
String recipient = mEtRecipientEmail.getText().toString().trim();
|
||||
|
||||
if (server.isEmpty()) {
|
||||
Toast.makeText(this, "请输入SMTP服务器地址", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (portStr.isEmpty()) {
|
||||
Toast.makeText(this, "请输入SMTP端口", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (sender.isEmpty()) {
|
||||
Toast.makeText(this, "请输入发件人邮箱", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (auth.isEmpty()) {
|
||||
Toast.makeText(this, "请输入邮箱授权码", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (recipient.isEmpty()) {
|
||||
Toast.makeText(this, "请输入收件人邮箱", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(this, "正在发送测试邮件...", Toast.LENGTH_SHORT).show();
|
||||
|
||||
final String finalRecipient = recipient;
|
||||
final String finalSender = sender;
|
||||
final String finalAuth = auth;
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final boolean success = SMTPUtils.sendTextMail(
|
||||
finalRecipient,
|
||||
"APPBase 测试邮件",
|
||||
"这是一封来自APPBase的测试邮件。\n\n发送时间: " + System.currentTimeMillis(),
|
||||
finalSender,
|
||||
finalAuth);
|
||||
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (success) {
|
||||
Toast.makeText(APPExcetionMailSettingsActivity.this,
|
||||
"测试邮件发送成功", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(APPExcetionMailSettingsActivity.this,
|
||||
"测试邮件发送失败,请检查设置", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
mSMTPConfigView = (SMTPConfigView) findViewById(R.id.smtp_config_view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,148 +3,11 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#FAFAFA"
|
||||
android:padding="16dp">
|
||||
android:background="#FAFAFA">
|
||||
|
||||
<LinearLayout
|
||||
<cc.winboll.studio.libappbase.views.SMTPConfigView
|
||||
android:id="@+id/smtp_config_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMTP 邮件发送设置"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#333333"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMTP 服务器"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_server"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textUri"
|
||||
android:hint="smtp.qq.com"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#000000"
|
||||
android:textColorHint="#999999"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMTP 端口"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_port"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
android:hint="465"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#000000"
|
||||
android:textColorHint="#999999"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发件人邮箱(QQ邮箱地址)"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_sender_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="123456@qq.com"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#000000"
|
||||
android:textColorHint="#999999"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="邮箱授权码(非QQ密码,在QQ邮箱设置中获取)"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_auth_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword"
|
||||
android:hint="请输入授权码"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#000000"
|
||||
android:textColorHint="#999999"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="收件人邮箱"
|
||||
android:textSize="13sp"
|
||||
android:textColor="#666666"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_recipient_email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textEmailAddress"
|
||||
android:hint="123456@qq.com"
|
||||
android:textSize="15sp"
|
||||
android:textColor="#000000"
|
||||
android:textColorHint="#999999"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="12dp"
|
||||
android:layout_marginBottom="24dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="保存设置"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="#007AFF"
|
||||
android:padding="14dp"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_test"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发送测试邮件"
|
||||
android:textSize="16sp"
|
||||
android:textColor="#007AFF"
|
||||
android:background="#FFFFFF"
|
||||
android:padding="14dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -26,4 +26,6 @@ android {
|
||||
|
||||
dependencies {
|
||||
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||
api 'com.sun.mail:android-mail:1.6.7'
|
||||
api 'com.sun.mail:android-activation:1.6.7'
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Tue Jul 21 14:10:49 HKT 2026
|
||||
stageCount=4
|
||||
#Thu Jul 23 19:07:39 HKT 2026
|
||||
stageCount=5
|
||||
libraryProject=libappbase
|
||||
baseVersion=15.21
|
||||
publishVersion=15.21.3
|
||||
publishVersion=15.21.4
|
||||
buildCount=0
|
||||
baseBetaVersion=15.21.4
|
||||
baseBetaVersion=15.21.5
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
package cc.winboll.studio.libappbase.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
import java.util.Properties;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Transport;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
/**
|
||||
* @Author 豆包&BigPickle&MiMo&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/07/23 17:36
|
||||
* @Describe APPMSG邮件发送工具类,使用QQ邮件SMTP服务发送邮件
|
||||
*/
|
||||
public class APPMSGMailUtils {
|
||||
|
||||
public static final String TAG = "APPMSGMailUtils";
|
||||
|
||||
//
|
||||
// SharedPreferences 配置
|
||||
//
|
||||
private static final String SP_NAME = "appmsg_mail_config";
|
||||
private static final String KEY_SMTP_SERVER = "smtp_server";
|
||||
private static final String KEY_SMTP_PORT = "smtp_port";
|
||||
private static final String KEY_SMTP_SENDER = "smtp_sender";
|
||||
private static final String KEY_SMTP_AUTH_CODE = "smtp_auth_code";
|
||||
private static final String KEY_SMTP_RECIPIENT = "smtp_recipient";
|
||||
private static final String KEY_SMTP_ENABLED = "smtp_enabled";
|
||||
|
||||
private static final String DEFAULT_SMTP_SERVER = "smtp.qq.com";
|
||||
private static final String DEFAULT_SMTP_PORT = "465";
|
||||
|
||||
//
|
||||
// 保存SMTP配置到SharedPreferences
|
||||
//
|
||||
public static void saveConfig(Context context, String server, String port,
|
||||
String sender, String authCode, String recipient) {
|
||||
LogUtils.d(TAG, "saveConfig: 开始保存SMTP配置");
|
||||
LogUtils.d(TAG, "saveConfig: server=" + server + ", port=" + port);
|
||||
LogUtils.d(TAG, "saveConfig: sender=" + sender + ", authCode长度=" + (authCode != null ? authCode.length() : 0));
|
||||
LogUtils.d(TAG, "saveConfig: recipient=" + recipient);
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putString(KEY_SMTP_SERVER, server);
|
||||
editor.putString(KEY_SMTP_PORT, port);
|
||||
editor.putString(KEY_SMTP_SENDER, sender);
|
||||
editor.putString(KEY_SMTP_AUTH_CODE, authCode);
|
||||
editor.putString(KEY_SMTP_RECIPIENT, recipient);
|
||||
editor.apply();
|
||||
LogUtils.d(TAG, "saveConfig: SMTP配置已保存完成");
|
||||
}
|
||||
|
||||
//
|
||||
// 从SharedPreferences读取SMTP配置
|
||||
//
|
||||
public static String getServer(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String value = sp.getString(KEY_SMTP_SERVER, DEFAULT_SMTP_SERVER);
|
||||
LogUtils.d(TAG, "getServer: " + value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getPort(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String value = sp.getString(KEY_SMTP_PORT, DEFAULT_SMTP_PORT);
|
||||
LogUtils.d(TAG, "getPort: " + value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getSender(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String value = sp.getString(KEY_SMTP_SENDER, "");
|
||||
LogUtils.d(TAG, "getSender: " + value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getAuthCode(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String value = sp.getString(KEY_SMTP_AUTH_CODE, "");
|
||||
LogUtils.d(TAG, "getAuthCode: 长度=" + (value != null ? value.length() : 0));
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String getRecipient(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
String value = sp.getString(KEY_SMTP_RECIPIENT, "");
|
||||
LogUtils.d(TAG, "getRecipient: " + value);
|
||||
return value;
|
||||
}
|
||||
|
||||
//
|
||||
// SMTP邮件发送开关
|
||||
//
|
||||
public static void setEnabled(Context context, boolean enabled) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putBoolean(KEY_SMTP_ENABLED, enabled);
|
||||
editor.apply();
|
||||
LogUtils.d(TAG, "setEnabled: " + enabled);
|
||||
}
|
||||
|
||||
public static boolean isEnabled(Context context) {
|
||||
SharedPreferences sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
|
||||
return sp.getBoolean(KEY_SMTP_ENABLED, false);
|
||||
}
|
||||
|
||||
//
|
||||
// 发送邮件(异步,在后台线程执行)
|
||||
//
|
||||
public static void sendMail(final Context context, final String subject,
|
||||
final String content, final String recipients) {
|
||||
LogUtils.d(TAG, "sendMail: ====== 开始调用sendMail ======");
|
||||
LogUtils.d(TAG, "sendMail: subject=" + subject);
|
||||
LogUtils.d(TAG, "sendMail: content长度=" + (content != null ? content.length() : 0));
|
||||
LogUtils.d(TAG, "sendMail: recipients=" + recipients);
|
||||
boolean enabled = isEnabled(context);
|
||||
LogUtils.d(TAG, "sendMail: isEnabled=" + enabled);
|
||||
if (!enabled) {
|
||||
LogUtils.d(TAG, "sendMail: SMTP邮件发送已禁用,跳过操作");
|
||||
return;
|
||||
}
|
||||
final String server = getServer(context);
|
||||
final String port = getPort(context);
|
||||
final String sender = getSender(context);
|
||||
final String authCode = getAuthCode(context);
|
||||
LogUtils.d(TAG, "sendMail: server=" + server + ", port=" + port);
|
||||
LogUtils.d(TAG, "sendMail: sender=" + sender + ", authCode长度=" + (authCode != null ? authCode.length() : 0));
|
||||
LogUtils.d(TAG, "sendMail: recipients=" + recipients);
|
||||
|
||||
if (sender == null || sender.length() == 0) {
|
||||
LogUtils.w(TAG, "sendMail: 请先配置发件人邮箱");
|
||||
showToast(context, "请先配置发件人邮箱");
|
||||
return;
|
||||
}
|
||||
if (authCode == null || authCode.length() == 0) {
|
||||
LogUtils.w(TAG, "sendMail: 请先配置邮箱授权码");
|
||||
showToast(context, "请先配置邮箱授权码");
|
||||
return;
|
||||
}
|
||||
if (recipients == null || recipients.length() == 0) {
|
||||
LogUtils.w(TAG, "sendMail: 收件人不能为空");
|
||||
showToast(context, "收件人不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, "sendMail: 参数校验通过,准备启动发送线程");
|
||||
showToast(context, "正在发送邮件...");
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "sendMail: 发送线程已启动");
|
||||
try {
|
||||
LogUtils.d(TAG, "sendMail: 创建邮件属性配置");
|
||||
Properties props = new Properties();
|
||||
props.put("mail.smtp.host", server);
|
||||
props.put("mail.smtp.port", port);
|
||||
props.put("mail.smtp.auth", "true");
|
||||
props.put("mail.smtp.socketFactory.port", port);
|
||||
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
|
||||
LogUtils.d(TAG, "sendMail: 创建邮件会话");
|
||||
Session session = Session.getInstance(props, new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
LogUtils.d(TAG, "sendMail: 身份验证回调触发");
|
||||
return new PasswordAuthentication(sender, authCode);
|
||||
}
|
||||
});
|
||||
|
||||
LogUtils.d(TAG, "sendMail: 创建MimeMessage");
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
message.setFrom(new InternetAddress(sender));
|
||||
message.setRecipients(javax.mail.Message.RecipientType.TO,
|
||||
InternetAddress.parse(recipients));
|
||||
message.setSubject(subject);
|
||||
message.setText(content);
|
||||
|
||||
LogUtils.d(TAG, "sendMail: 调用Transport.send开始发送");
|
||||
Transport.send(message);
|
||||
|
||||
LogUtils.d(TAG, "sendMail: 邮件发送成功");
|
||||
showToast(context, "邮件发送成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "sendMail: 邮件发送异常", e);
|
||||
showToast(context, "邮件发送失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
LogUtils.d(TAG, "sendMail: ====== sendMail调用结束 ======");
|
||||
}
|
||||
|
||||
//
|
||||
// 在主线程显示Toast提示
|
||||
//
|
||||
private static void showToast(final Context context, final String message) {
|
||||
if (context == null || message == null) {
|
||||
return;
|
||||
}
|
||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(context.getApplicationContext(),
|
||||
message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,30 @@ public final class SMTPUtils {
|
||||
final String body,
|
||||
final String from,
|
||||
final String authCode) {
|
||||
return sendMail(to, subject, body, from, authCode, false);
|
||||
return sendMail(to, subject, body, from, authCode, false,
|
||||
DEFAULT_SMTP_HOST, DEFAULT_SMTP_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送纯文本邮件(自定义SMTP服务器)
|
||||
* @param to 收件人邮箱地址
|
||||
* @param subject 邮件主题
|
||||
* @param body 邮件正文(纯文本)
|
||||
* @param from 发件人邮箱地址
|
||||
* @param authCode 邮箱授权码
|
||||
* @param host SMTP服务器地址
|
||||
* @param port SMTP端口
|
||||
* @return true=发送成功,false=发送失败
|
||||
*/
|
||||
public static boolean sendTextMail(
|
||||
final String to,
|
||||
final String subject,
|
||||
final String body,
|
||||
final String from,
|
||||
final String authCode,
|
||||
final String host,
|
||||
final int port) {
|
||||
return sendMail(to, subject, body, from, authCode, false, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,7 +88,30 @@ public final class SMTPUtils {
|
||||
final String body,
|
||||
final String from,
|
||||
final String authCode) {
|
||||
return sendMail(to, subject, body, from, authCode, true);
|
||||
return sendMail(to, subject, body, from, authCode, true,
|
||||
DEFAULT_SMTP_HOST, DEFAULT_SMTP_PORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTML邮件(自定义SMTP服务器)
|
||||
* @param to 收件人邮箱地址
|
||||
* @param subject 邮件主题
|
||||
* @param body 邮件正文(HTML格式)
|
||||
* @param from 发件人邮箱地址
|
||||
* @param authCode 邮箱授权码
|
||||
* @param host SMTP服务器地址
|
||||
* @param port SMTP端口
|
||||
* @return true=发送成功,false=发送失败
|
||||
*/
|
||||
public static boolean sendHtmlMail(
|
||||
final String to,
|
||||
final String subject,
|
||||
final String body,
|
||||
final String from,
|
||||
final String authCode,
|
||||
final String host,
|
||||
final int port) {
|
||||
return sendMail(to, subject, body, from, authCode, true, host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,9 +130,12 @@ public final class SMTPUtils {
|
||||
final String body,
|
||||
final String from,
|
||||
final String authCode,
|
||||
final boolean isHtml) {
|
||||
final boolean isHtml,
|
||||
final String host,
|
||||
final int port) {
|
||||
|
||||
LogUtils.d(TAG, "sendMail invoke, to=" + to + ", subject=" + subject + ", isHtml=" + isHtml);
|
||||
LogUtils.d(TAG, "sendMail invoke, to=" + to + ", subject=" + subject
|
||||
+ ", isHtml=" + isHtml + ", host=" + host + ":" + port);
|
||||
|
||||
// 参数校验
|
||||
if (to == null || to.isEmpty()) {
|
||||
@@ -108,9 +157,9 @@ public final class SMTPUtils {
|
||||
|
||||
try {
|
||||
// 1. 创建SSL连接
|
||||
LogUtils.d(TAG, " connecting to " + DEFAULT_SMTP_HOST + ":" + DEFAULT_SMTP_PORT);
|
||||
LogUtils.d(TAG, " connecting to " + host + ":" + port);
|
||||
SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
|
||||
socket = factory.createSocket(DEFAULT_SMTP_HOST, DEFAULT_SMTP_PORT);
|
||||
socket = factory.createSocket(host, port);
|
||||
socket.setSoTimeout(10000);
|
||||
|
||||
reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package cc.winboll.studio.libappbase.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.R;
|
||||
import cc.winboll.studio.libappbase.utils.APPMSGMailUtils;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* @Author 豆包&BigPickle&MiMo&ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2026/07/23 17:35
|
||||
* @Describe SMTP邮件配置视图控件,用于设置QQ邮件SMTP服务参数
|
||||
*/
|
||||
public class SMTPConfigView extends LinearLayout {
|
||||
|
||||
public static final String TAG = "SMTPConfigView";
|
||||
|
||||
private EditText mEtServer;
|
||||
private EditText mEtPort;
|
||||
private EditText mEtSender;
|
||||
private EditText mEtAuthCode;
|
||||
private EditText mEtRecipient;
|
||||
private CheckBox mCbEnabled;
|
||||
|
||||
public SMTPConfigView(Context context) {
|
||||
super(context);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
public SMTPConfigView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView(context);
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
LogUtils.d(TAG, "initView: 初始化SMTP配置视图");
|
||||
View.inflate(context, R.layout.view_smtp_config, this);
|
||||
|
||||
mEtServer = (EditText) findViewById(R.id.et_smtp_server);
|
||||
mEtPort = (EditText) findViewById(R.id.et_smtp_port);
|
||||
mEtSender = (EditText) findViewById(R.id.et_smtp_sender);
|
||||
mEtAuthCode = (EditText) findViewById(R.id.et_smtp_auth_code);
|
||||
mEtRecipient = (EditText) findViewById(R.id.et_smtp_recipient);
|
||||
mCbEnabled = (CheckBox) findViewById(R.id.cb_smtp_enabled);
|
||||
|
||||
mCbEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
APPMSGMailUtils.setEnabled(getContext(), isChecked);
|
||||
}
|
||||
});
|
||||
|
||||
// 加载已保存的配置
|
||||
loadConfig();
|
||||
|
||||
// 保存按钮点击事件
|
||||
findViewById(R.id.btn_smtp_save).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
saveConfig();
|
||||
}
|
||||
});
|
||||
|
||||
// 发送测试邮件按钮点击事件
|
||||
findViewById(R.id.btn_smtp_test_send).setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
saveConfig();
|
||||
Context ctx = getContext();
|
||||
String recipient = mEtRecipient.getText().toString().trim();
|
||||
APPMSGMailUtils.sendMail(ctx, "SMTP测试邮件",
|
||||
"这是一封SMTP配置测试邮件。如果您收到此邮件,说明SMTP配置正确。",
|
||||
recipient);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// 从SharedPreferences加载已保存的SMTP配置
|
||||
//
|
||||
private void loadConfig() {
|
||||
Context context = getContext();
|
||||
mEtServer.setText(APPMSGMailUtils.getServer(context));
|
||||
mEtPort.setText(APPMSGMailUtils.getPort(context));
|
||||
mEtSender.setText(APPMSGMailUtils.getSender(context));
|
||||
mEtAuthCode.setText(APPMSGMailUtils.getAuthCode(context));
|
||||
mEtRecipient.setText(APPMSGMailUtils.getRecipient(context));
|
||||
mCbEnabled.setChecked(APPMSGMailUtils.isEnabled(context));
|
||||
LogUtils.d(TAG, "loadConfig: SMTP配置已加载");
|
||||
}
|
||||
|
||||
//
|
||||
// 将当前输入的SMTP配置保存到SharedPreferences
|
||||
//
|
||||
private void saveConfig() {
|
||||
Context context = getContext();
|
||||
String server = mEtServer.getText().toString().trim();
|
||||
String port = mEtPort.getText().toString().trim();
|
||||
String sender = mEtSender.getText().toString().trim();
|
||||
String authCode = mEtAuthCode.getText().toString().trim();
|
||||
String recipient = mEtRecipient.getText().toString().trim();
|
||||
|
||||
APPMSGMailUtils.saveConfig(context, server, port, sender, authCode, recipient);
|
||||
Toast.makeText(context, "SMTP配置已保存", Toast.LENGTH_SHORT).show();
|
||||
LogUtils.d(TAG, "saveConfig: SMTP配置已保存");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp"
|
||||
android:background="@drawable/bg_container_border">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMTP邮件配置"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SMTP服务器"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_server"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="smtp.qq.com"
|
||||
android:inputType="textUri"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="端口"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_port"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="465"
|
||||
android:inputType="number"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发件人邮箱"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_sender"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="your@qq.com"
|
||||
android:inputType="textEmailAddress"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="授权码"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_auth_code"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="QQ邮箱授权码"
|
||||
android:inputType="textPassword"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="默认收件人"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_smtp_recipient"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="recipient@example.com"
|
||||
android:inputType="textEmailAddress"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cb_smtp_enabled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="启用SMTP邮件发送"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginTop="12dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_smtp_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="保存配置"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_smtp_test_send"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="发送测试邮件"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
Reference in New Issue
Block a user