168 lines
6.2 KiB
C#
168 lines
6.2 KiB
C#
using System;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Android power control entry point.
|
|
/// Real device shutdown requires firmware support, system signature, or a vendor broadcast receiver.
|
|
/// </summary>
|
|
public static class AndroidPowerController
|
|
{
|
|
private const string DefaultShutdownBroadcastAction = "com.dcx.ruiyiweiux.ACTION_SHUTDOWN";
|
|
private const string RequestShutdownAction = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
|
|
private const string InternalRequestShutdownAction = "com.android.internal.intent.action.REQUEST_SHUTDOWN";
|
|
private const string KeyConfirmExtra = "android.intent.extra.KEY_CONFIRM";
|
|
|
|
public static bool TryShutdownDevice()
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
bool broadcastSent = SendShutdownBroadcast(GetShutdownBroadcastAction());
|
|
bool requestStarted = StartAndroidShutdownRequest(RequestShutdownAction);
|
|
bool internalRequestStarted = StartAndroidShutdownRequest(InternalRequestShutdownAction);
|
|
bool shellCommandStarted = TryExecuteShutdownCommand();
|
|
|
|
if (!broadcastSent && !requestStarted && !internalRequestStarted && !shellCommandStarted)
|
|
{
|
|
Debug.LogWarning("AndroidPowerController: 关机请求未发送成功,将回退为退出应用");
|
|
return false;
|
|
}
|
|
|
|
Debug.Log($"AndroidPowerController: 关机请求结果 broadcast={broadcastSent}, request={requestStarted}, internalRequest={internalRequestStarted}, shell={shellCommandStarted}");
|
|
return requestStarted || internalRequestStarted || shellCommandStarted;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
private static bool SendShutdownBroadcast(string action)
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
try
|
|
{
|
|
using (var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
|
using (var activity = unityClass.GetStatic<AndroidJavaObject>("currentActivity"))
|
|
using (var intent = new AndroidJavaObject("android.content.Intent", action))
|
|
{
|
|
intent.Call<AndroidJavaObject>("putExtra", "reason", "user_exit");
|
|
intent.Call<AndroidJavaObject>("putExtra", "confirm", false);
|
|
activity.Call("sendBroadcast", intent);
|
|
Debug.Log($"AndroidPowerController: 已发送关机广播 {action}");
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"AndroidPowerController: 发送关机广播失败: {ex.Message}");
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
private static string GetShutdownBroadcastAction()
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
try
|
|
{
|
|
string configuredAction = ReadShutdownBroadcastAction(Path.Combine(Application.persistentDataPath, "config_android.ini"));
|
|
if (!string.IsNullOrEmpty(configuredAction))
|
|
{
|
|
return configuredAction;
|
|
}
|
|
|
|
configuredAction = ReadShutdownBroadcastAction(Path.Combine(Application.streamingAssetsPath, "config_android.ini"));
|
|
if (!string.IsNullOrEmpty(configuredAction))
|
|
{
|
|
return configuredAction;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"AndroidPowerController: 读取关机广播配置失败: {ex.Message}");
|
|
}
|
|
#endif
|
|
|
|
return DefaultShutdownBroadcastAction;
|
|
}
|
|
|
|
private static string ReadShutdownBroadcastAction(string configPath)
|
|
{
|
|
if (string.IsNullOrEmpty(configPath) || !File.Exists(configPath))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
foreach (var line in File.ReadAllLines(configPath))
|
|
{
|
|
if (line.StartsWith("shutdownBroadcastAction=", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return line.Substring("shutdownBroadcastAction=".Length).Trim();
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static bool StartAndroidShutdownRequest(string action)
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
try
|
|
{
|
|
using (var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
|
using (var activity = unityClass.GetStatic<AndroidJavaObject>("currentActivity"))
|
|
using (var intent = new AndroidJavaObject("android.content.Intent", action))
|
|
{
|
|
intent.Call<AndroidJavaObject>("putExtra", KeyConfirmExtra, false);
|
|
intent.Call<AndroidJavaObject>("putExtra", "android.intent.extra.USER_REQUESTED_SHUTDOWN", true);
|
|
intent.Call<AndroidJavaObject>("addFlags", 0x10000000); // FLAG_ACTIVITY_NEW_TASK
|
|
activity.Call("startActivity", intent);
|
|
Debug.Log($"AndroidPowerController: 已发起系统关机请求 {action}");
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"AndroidPowerController: 系统关机请求失败 {action}: {ex.Message}");
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
private static bool TryExecuteShutdownCommand()
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
return TryExecuteShellCommand("su -c reboot -p") ||
|
|
TryExecuteShellCommand("reboot -p") ||
|
|
TryExecuteShellCommand("svc power shutdown");
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
private static bool TryExecuteShellCommand(string command)
|
|
{
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|
try
|
|
{
|
|
using (var runtime = new AndroidJavaClass("java.lang.Runtime"))
|
|
using (var currentRuntime = runtime.CallStatic<AndroidJavaObject>("getRuntime"))
|
|
{
|
|
currentRuntime.Call<AndroidJavaObject>("exec", command);
|
|
Debug.Log($"AndroidPowerController: 已执行关机命令 {command}");
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"AndroidPowerController: 执行关机命令失败 {command}: {ex.Message}");
|
|
return false;
|
|
}
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
}
|