一、项目介绍
在某些嵌入式 Android、物联网盒子或特殊工业场景中,需要在预设时间自动开机或关机,以便节能或定时执行任务。标准 Android 手机并不支持任意时刻自动开机,但部分设备厂商或定制固件提供了相关接口。通常思路包括:
开机时间写入底层 RTC:在关机前通过 AlarmManager 或直接写入 /sys/class/rtc/rtc0/wakealarm 实现;
关机定时:使用 PowerManager.reboot() 或发送关机广播;
用户界面:提供设置界面,选择开、关机时刻,并在后台调度任务;
权限与系统签名:关机、重启等操作通常需要系统权限或签名,普通应用需借助 ROOT 或系统应用。
本教程假设设备已授予系统签名权限或 ROOT 环境,可执行开关机命令;并演示如何:
在应用内 设置开/关机时间
使用 AlarmManager 安排关机或写入 Wake Alarm
调用 PowerManager 或 Runtime.exec() 发送关机命令
处理重复定时和 取消
UI 采用 TimePicker 选择时间,并保存到 SharedPreferences
二、相关技术与知识
AlarmManager
用于安排在未来某个时间发送广播或启动 Service。
setExactAndAllowWhileIdle() 保证在 Doze 模式下精准触发。
RTC Wake Alarm
通过向 /sys/class/rtc/rtc0/wakealarm 写入时间戳,设置下次开机唤醒。
Android 系统原生支持 AlarmManager.setRtcWakeup(),但底层实现可兼容写文件。
关机/重启命令
普通应用:Intent 调用 ACTION_REQUEST_SHUTDOWN(需权限),可唤起关机界面;
系统应用/ROOT:通过 PowerManager.reboot(null) 或 Runtime.getRuntime().exec("reboot -p") 强制关机;
TimePicker & SharedPreferences
TimePickerDialog 选时;
将选择结果保存到 SharedPreferences,以便重启后读取计划。
Foreground Service
如果需要在后台长期运行,可使用前台服务维持进程不被杀死;提供通知栏入口。
设备兼容性
不同 Android 版本对关机命令权限控制不同,需根据设备定制;
部分设备在未获得系统签名时,无法写 /sys 或调用 PowerManager.reboot()。
三、实现思路
UI 设计
两个按钮:设置“定时开机”和“定时关机”;
分别弹出 TimePickerDialog 供用户选择时分;
列表展示当前已设置的任务,并可取消。
数据存储
使用 SharedPreferences 存储 bootTime 和 shutdownTime(24h格式 “HH:mm”);
可扩展为多条计划,使用 Room 存储。
定时调度
关机:在用户设定的 shutdownTime 到来时,AlarmManager 发送广播到 ShutdownReceiver,在 onReceive 中调用关机逻辑;
开机:在关机前写入 RTC Wake Alarm,或在系统启动后读取 bootTime 并再次设定下一次关机等。
执行开/关机
关机:如果是系统应用,可直接 PowerManager pm = getSystemService(PowerManager.class); pm.reboot(null); 或 exec("reboot -p");
开机:由底层通过 RTC 唤醒,不在应用层执行;应用可在 BOOT_COMPLETED 广播中监听,并在开机时执行初始化任务。
权限申请
运行时申请 RECEIVE_BOOT_COMPLETED、REQUEST_SHUTDOWN 等;
关机权限 android.permission.SHUTDOWN 通常为系统权限。
四、完整代码
// ==============================================
// 文件:MainActivity.java
// 功能:定时开关机设置、调度与执行示例
// 包含:布局 XML、Manifest、Receiver、一处整合
// ==============================================
package com.example.timerpower;
import android.app.*;
import android.content.*;
import android.os.*;
import android.provider.Settings;
import android.widget.*;
import androidx.annotation.*;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private Button btnSetBoot, btnSetShutdown;
private TextView tvInfo;
private SharedPreferences prefs;
@Override
protected void onCreate(Bundle s) {
super.onCreate(s);
setContentView(R.layout.activity_main);
btnSetBoot = findViewById(R.id.btnSetBoot);
btnSetShutdown = findViewById(R.id.btnSetShutdown);
tvInfo = findViewById(R.id.tvInfo);
prefs = getSharedPreferences("timer_power", MODE_PRIVATE);
updateInfo();
btnSetBoot.setOnClickListener(v -> showTimePicker(true));
btnSetShutdown.setOnClickListener(v -> showTimePicker(false));
}
private void showTimePicker(boolean isBoot) {
Calendar c = Calendar.getInstance();
new TimePickerDialog(this,
(view, h, m) -> {
String key = isBoot ? "bootTime" : "shutdownTime";
prefs.edit().putString(key,
String.format("%02d:%02d", h, m)).apply();
schedule(isBoot, h, m);
updateInfo();
},
c.get(Calendar.HOUR_OF_DAY),
c.get(Calendar.MINUTE), true).show();
}
private void updateInfo() {
String boot = prefs.getString("bootTime", "--:--");
String off = prefs.getString("shutdownTime", "--:--");
tvInfo.setText("开机: " + boot + "\n关机: " + off);
}
private void schedule(boolean isBoot, int h, int m) {
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this,
isBoot ? BootReceiver.class : ShutdownReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(this,
isBoot? 0:1, intent, 0);
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, h);
c.set(Calendar.MINUTE, m);
c.set(Calendar.SECOND, 0);
long trigger = c.getTimeInMillis();
if (trigger < System.currentTimeMillis())
trigger += 24*3600*1000; // 次日
am.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP, trigger, pi);
}
}
// ------- 关机 Receiver -------
public class ShutdownReceiver extends BroadcastReceiver {
@Override public void onReceive(Context ctx, Intent i) {
try {
// 系统关机
Process p = Runtime.getRuntime()
.exec(new String[]{"su","-c","reboot -p"});
p.waitFor();
} catch (Exception e) { e.printStackTrace(); }
}
}
// ------- 开机 Receiver -------
public class BootReceiver extends BroadcastReceiver {
@Override public void onReceive(Context ctx, Intent i) {
// 在系统启动后可执行初始化逻辑
Toast.makeText(ctx,
"定时开机已到", Toast.LENGTH_LONG).show();
}
}
/*
=========================== res/layout/activity_main.xml ===========================
android:orientation="vertical" android:padding="16dp" android:layout_width="match_parent" android:layout_height="match_parent"> android:text="--" android:textSize="18sp" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
*/
/*
=========================== AndroidManifest.xml ===========================
package="com.example.timerpower">
*/
五、方法解读
AlarmManager & RTC_WAKEUP:利用系统闹钟在指定时间触发广播,结合 su reboot -p 强制关机。
BootCompleted:设备每次开机后,应用无需启动即可接收广播,执行后续逻辑。
TimePickerDialog:在 UI 层获取用户设定的时分,并保存到 SharedPreferences。
权限与兼容:执行关机命令需 ROOT 或系统签名权限;普通应用仅可唤起关机界面。
六、项目总结
适用场景:定制化设备、物联网、智能盒子等需定时开关机的环境;
限制:绝大多数普通 Android 手机不支持应用层定时开机,需底层厂商支持;
扩展:可增加“重复”属性(每天/每周)、多条计划列表、取消计划功能;
安全:Root/系统权限操作需谨慎,避免恶意使用;
提示:请根据目标设备特性(是否支持 su、定制固件)调整方案。