Android设置NTP时间服务器API及权限问题求解
解决方案:Xamarin.Forms修改Android NTP服务器权限问题
问题本质
直接调用/system/bin/settings命令修改NTP服务器的方式,普通应用(非Root、非系统签名)无法实现。报错里的INTERACT_ACROSS_USERS是Android的签名保护权限,只有系统签名的应用或者Root权限进程才能获取,就算在AndroidManifest.xml里声明也不会被系统授予。
可行方案分情况讨论
1. 设备已Root
如果设备有Root权限,可以通过su命令以Root身份执行settings命令,绕过权限检查。修改你的C#代码如下:
public void SetTimeServer(string timeServer) { var process = new System.Diagnostics.Process(); // 用su执行命令,-c参数指定要执行的内容 process.StartInfo.FileName = @"/system/bin/su"; process.StartInfo.Arguments = $"-c \"settings put global ntp_server {timeServer}\""; process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardInput = false; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.OutputDataReceived += (sender, e) => { System.Diagnostics.Debug.WriteLine(e.Data); }; process.ErrorDataReceived += (sender, e) => { System.Diagnostics.Debug.WriteLine(e.Data); }; try { process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"执行失败:{ex.Message}"); } }
注意:部分设备的su路径可能是/su/bin/su,如果报错可以尝试替换路径。
2. 应用为系统签名应用
如果你的应用是预装的系统应用,可以通过系统签名获取权限:
- 获取对应Android设备的系统签名密钥(比如AOSP的
platform.pk8和platform.x509.pem) - 在Xamarin项目中配置用该密钥签名APK
- 将APK安装到系统目录(
/system/app或/system/priv-app) - 此时
AndroidManifest.xml中声明的INTERACT_ACROSS_USERS权限会被系统授予,原代码即可正常运行。
3. 无Root且非系统应用(替代方案)
普通应用无法修改系统NTP服务器设置,只能在应用内部实现独立的NTP时间同步。可以使用以下代码自行实现NTP客户端:
using System.Net.Sockets; using System.Net; using System.Threading.Tasks; public async Task<DateTime> GetNtpTime(string ntpServer) { var ntpData = new byte[48]; ntpData[0] = 0x1B; // 设置NTP版本号和模式 using (var udpClient = new UdpClient()) { await udpClient.ConnectAsync(ntpServer, 123); await udpClient.SendAsync(ntpData, ntpData.Length); var receivedData = await udpClient.ReceiveAsync(); // 解析NTP返回的时间数据(从1900年开始的秒数) ulong intPart = BitConverter.ToUInt32(receivedData.Buffer, 40); ulong fracPart = BitConverter.ToUInt32(receivedData.Buffer, 44); intPart = SwapEndianness(intPart); fracPart = SwapEndianness(fracPart); var milliseconds = (intPart * 1000) + ((fracPart * 1000) / 0x100000000L); var ntpTime = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(milliseconds); return ntpTime.ToLocalTime(); } } private uint SwapEndianness(ulong x) { return (uint)(((x & 0x000000FF) << 24) + ((x & 0x0000FF00) << 8) + ((x & 0x00FF0000) >> 8) + ((x & 0xFF000000) >> 24)); }
调用这个方法可以在应用内获取NTP时间,无需修改系统设置。
内容的提问来源于stack exchange,提问作者Ken K
相关产品推荐
相关产品推荐

