You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android开发:每隔N秒检测网络连接及短信触发发邮件的实现方法

Hey,刚好这两个需求我之前在项目里都实现过,给你整理了适配Android新版本的具体方案,都是经过实际测试可行的:

一、每隔N秒检测网络连接状态

这里推荐两种方案,根据你的使用场景选择:

方案1:使用WorkManager(优先推荐,适配Android 8+后台限制)

现在Android后台管控越来越严,Handler在后台很容易被系统杀死,WorkManager是Google官方推荐的后台任务调度工具,能保证任务在合适的时机执行。

步骤:

  1. 先添加WorkManager依赖(在build.gradle(app)中):
dependencies {
    implementation "androidx.work:work-runtime:2.8.1"
}
  1. 实现自定义Worker类,封装网络检测逻辑:
public class NetworkCheckWorker extends Worker {
    private static final String TAG = "NetworkCheckWorker";

    public NetworkCheckWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 检测当前网络状态
        boolean isConnected = checkNetworkStatus(getApplicationContext());
        Log.d(TAG, "当前网络状态:" + (isConnected ? "已连接" : "未连接"));
        
        // 这里可以根据状态做你需要的操作,比如发送通知、同步数据等

        // 如果需要持续循环检测,调度下一次任务(WorkManager的PeriodicWorkRequest最小间隔是15分钟,短间隔用这个方式)
        long interval = getInputData().getLong("CHECK_INTERVAL", 10000); // 默认10秒
        OneTimeWorkRequest nextCheck = new OneTimeWorkRequest.Builder(NetworkCheckWorker.class)
                .setInitialDelay(interval, TimeUnit.MILLISECONDS)
                .setInputData(new Data.Builder()
                        .putLong("CHECK_INTERVAL", interval)
                        .build())
                .build();
        WorkManager.getInstance(getApplicationContext()).enqueue(nextCheck);

        return Result.success();
    }

    // 工具方法:检测网络连接
    private boolean checkNetworkStatus(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) return false;

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Network network = cm.getActiveNetwork();
            NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
            return capabilities != null && 
                   (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || 
                    capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
        } else {
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
        }
    }
}
  1. 在Activity或Application中启动检测任务:
// 设置检测间隔为10秒(可自行修改)
long checkInterval = 10000;
OneTimeWorkRequest initialCheck = new OneTimeWorkRequest.Builder(NetworkCheckWorker.class)
        .setInputData(new Data.Builder()
                .putLong("CHECK_INTERVAL", checkInterval)
                .build())
        .build();
WorkManager.getInstance(this).enqueue(initialCheck);

注意点:

  • 需要在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  • 如果检测间隔大于等于15分钟,直接用PeriodicWorkRequest更简洁,不用手动调度下一次任务。

方案2:Handler+Runnable(适合前台持续运行场景)

如果你的App一直在前台运行,用Handler更轻量,不需要依赖额外库:

private Handler mNetworkHandler = new Handler(Looper.getMainLooper());
private Runnable mCheckRunnable;
private final long CHECK_INTERVAL = 10000; // 10秒

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mCheckRunnable = new Runnable() {
        @Override
        public void run() {
            boolean isConnected = checkNetworkStatus(MainActivity.this);
            Log.d("NetworkCheck", "当前网络:" + (isConnected ? "正常" : "断开"));
            // 循环执行
            mNetworkHandler.postDelayed(this, CHECK_INTERVAL);
        }
    };

    // 启动检测
    mNetworkHandler.post(mCheckRunnable);
}

// 页面销毁时一定要停止,避免内存泄漏
@Override
protected void onDestroy() {
    super.onDestroy();
    mNetworkHandler.removeCallbacks(mCheckRunnable);
}

// 同上面的checkNetworkStatus方法
private boolean checkNetworkStatus(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (cm == null) return false;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Network network = cm.getActiveNetwork();
        NetworkCapabilities capabilities = cm.getNetworkCapabilities(network);
        return capabilities != null && 
               (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || 
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
    } else {
        NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
    }
}

注意点:

  • App进入后台后,系统可能会杀死进程,导致检测停止,所以只适合前台场景。

二、收到短信时自动发送邮件

这个需求需要完成短信监听邮件发送两个核心部分,还要注意Android新版本的权限和后台限制:

步骤1:申请必要权限

AndroidManifest.xml中添加:

<!-- 读取短信权限(危险权限,需动态申请) -->
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 接收广播权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<!-- 网络权限,用于发送邮件 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Android 8+前台服务权限,保证后台能发送邮件 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

步骤2:动态注册短信广播接收器

Android 8.0之后,静态注册的SMS_RECEIVED广播会被系统拦截,必须动态注册:

public class MainActivity extends AppCompatActivity {
    private SmsReceiver mSmsReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 先申请读取短信权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS}, 1001);
        } else {
            registerSmsListener();
        }
    }

    private void registerSmsListener() {
        mSmsReceiver = new SmsReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.provider.Telephony.SMS_RECEIVED");
        filter.setPriority(Integer.MAX_VALUE); // 确保优先收到短信广播
        registerReceiver(mSmsReceiver, filter);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1001) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                registerSmsListener();
            } else {
                Toast.makeText(this, "需要读取短信权限才能实现功能", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销广播,避免内存泄漏
        if (mSmsReceiver != null) {
            unregisterReceiver(mSmsReceiver);
        }
    }
}

步骤3:实现短信接收器和邮件发送逻辑

public class SmsReceiver extends BroadcastReceiver {
    private static final String TAG = "SmsReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if ("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())) {
            Bundle bundle = intent.getExtras();
            if (bundle == null) return;

            Object[] pdus = (Object[]) bundle.get("pdus");
            if (pdus == null) return;

            for (Object pdu : pdus) {
                SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
                String sender = sms.getDisplayOriginatingAddress();
                String content = sms.getMessageBody();
                Log.d(TAG, "收到短信:来自" + sender + ",内容:" + content);

                // 可选:添加过滤逻辑,比如只处理特定号码的短信
                // if ("10086".equals(sender)) { ... }

                // 后台发送邮件,避免在广播接收器中做耗时操作
                sendEmailInBackground(context, sender, content);
            }
        }
    }

    private void sendEmailInBackground(Context context, String sender, String content) {
        // 用Coroutine做后台任务(需要添加Coroutine依赖)
        CoroutineScope(Dispatchers.IO).launch {
            boolean success = sendEmail("你的邮箱地址", "收件人邮箱地址", "新短信通知", "发件人:" + sender + "\n短信内容:" + content);
            // 发送通知告知用户结果
            showNotification(context, success ? "邮件发送成功" : "邮件发送失败", 
                            success ? "短信内容已发送至指定邮箱" : "请检查网络或邮箱配置");
        }
    }

    // 邮件发送核心方法(用JavaMail实现)
    private boolean sendEmail(String fromEmail, String toEmail, String subject, String body) {
        try {
            Properties props = new Properties();
            // 这里以QQ邮箱为例,其他邮箱修改对应的SMTP地址和端口
            props.put("mail.smtp.host", "smtp.qq.com");
            props.put("mail.smtp.port", "587");
            props.put("mail.smtp.auth", "true");
            props.put("mail.smtp.starttls.enable", "true");

            Session session = Session.getInstance(props, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    // 注意:这里填邮箱的授权码,不是登录密码!
                    return new PasswordAuthentication(fromEmail, "你的邮箱授权码");
                }
            });

            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(fromEmail));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail));
            message.setSubject(subject);
            message.setText(body);

            Transport.send(message);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 显示通知的工具方法
    private void showNotification(Context context, String title, String content) {
        NotificationManagerCompat manager = NotificationManagerCompat.from(context);

        // Android 8+需要创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("SMS_EMAIL_CHANNEL", "短信转邮件通知", NotificationManager.IMPORTANCE_DEFAULT);
            manager.createNotificationChannel(channel);
        }

        Notification notification = new NotificationCompat.Builder(context, "SMS_EMAIL_CHANNEL")
                .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标
                .setContentTitle(title)
                .setContentText(content)
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .build();

        manager.notify(1, notification);
    }
}

步骤4:添加依赖(JavaMail和Coroutine)

build.gradle(app)中添加:

android {
    packagingOptions {
        pickFirst 'META-INF/LICENSE.txt'
        pickFirst 'META-INF/NOTICE.txt'
    }
}

dependencies {
    // JavaMail依赖
    implementation 'com.sun.mail:android-mail:1.6.7'
    implementation 'com.sun.mail:android-activation:1.6.7'
    // Coroutine依赖(用于后台任务)
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}

注意点:

  • 邮箱授权码:需要在邮箱设置中开启POP3/SMTP服务,然后获取授权码(比如QQ邮箱、163邮箱都有这个选项)。
  • Android后台限制:如果需要App在后台也能触发邮件发送,建议把邮件逻辑放到WorkManager中,避免广播接收器被系统限制。
  • 短信过滤:建议添加过滤逻辑,只处理你需要的短信,避免不必要的邮件发送。

内容的提问来源于stack exchange,提问作者mohamadrezach

火山引擎 最新活动