Android App 设置系统时间,语言和时区、系统重启

本文介绍如何在Android系统中修改系统时间、日期、时区和语言,包括手动设置和自动获取的配置方法,适用于拥有系统签名的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明

以下功能的实现是在有系统签名和设置了 android:sharedUserId=“android.uid.system” 的情况下实现的。如果你的应用没有系统签名,可能无法实现以下功能。

1. 修改系统时间

设置系统时间,首先需要保证app的uid为system,关于如何设置uid,可以看看这篇 App设置系统签名

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.xxx.xxx"
  android:sharedUserId="android.uid.system">

并给予相应的权限:

    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
    <uses-permission android:name="android.permission.SET_TIME_ZONE" />

设置系统时间,主要是通过 Calendar 进行日期的设定,通过 Calendar.getTimeInMillis() 获取毫秒数,再通过 SystemClock.setCurrentTimeMillis() 来进行设置。

1. 设置系统时间(仅设置xx:xx)

 /** 设置系统时间*/
    @Throws(IOException::class)
    fun setTime(hour: Int, minute: Int) {
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.HOUR_OF_DAY, hour)
        calendar.set(Calendar.MINUTE, minute)
        val timeMills: Long = calendar.timeInMillis
        SystemClock.setCurrentTimeMillis(timeMills)
    }

2. 设置系统日期(仅设置到xxxx年xx月xx日)

/** 设置系统日期*/
    @Throws(IOException::class)
    fun setDate(year: Int, month: Int, day: Int) {
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.YEAR, year)
        calendar.set(Calendar.MONTH, month)
        calendar.set(Calendar.DAY_OF_MONTH, day)
        val timeMills: Long = calendar.timeInMillis
        SystemClock.setCurrentTimeMillis(timeMills)
    }

3.设置系统是否自动获取时间


    /**
     * 设置系统是否自动获取时间
     * @param context Activity's context.
     * @param checked If checked > 0, it will auto set date.
     */
    fun setAutoDateTime(context: Context, checked: Int) {
        Settings.Global.putInt(
            context.contentResolver,
            Settings.Global.AUTO_TIME, checked
        )
    }
4.判断系统是否自动获取时间

    /**
     * 判断系统是否自动获取时间
     * @param context Activity's context.
     * @return If date is auto setting.
     */
    fun checkDateAutoSet(context: Context): Boolean {
        return try {
            Settings.Global.getInt(
                context.contentResolver,
                Settings.Global.AUTO_TIME
            ) > 0
        } catch (exception: SettingNotFoundException) {
            exception.printStackTrace()
            false
        }
    }

2. 修改系统时区

系统是通过 AlarmManager 来修改 TimeZone 的。也需要权限:

  <uses-permission android:name="android.permission.SET_TIME_ZONE" />

1. 设置系统时区

/** 设置系统时区*/
    fun setTimeZone(context: Context, timeZone: String?) {
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        alarmManager.setTimeZone(timeZone)
    }

2. 设置系统是否自动获取时区

/**
     * 设置系统是否自动获取时区
     * @param context Activity's context.
     * @param checked If checked > 0, it will auto set timezone.
     */
    fun setAutoTimeZone(context: Context, checked: Int) {
        Settings.Global.putInt(
            context.contentResolver,
            Settings.Global.AUTO_TIME_ZONE, checked
        )
    }

3. 判断系统是否自动获取时区

 /**
     * 判断系统是否自动获取时区
     * @param context Activity's context.
     * @return If timezone is auto setting.
     */
    fun checkTimeZoneAutoSet(context: Context): Boolean {
        return try {
            Settings.Global.getInt(
                context.contentResolver,
                Settings.Global.AUTO_TIME_ZONE
            ) > 0
        } catch (exception: SettingNotFoundException) {
            exception.printStackTrace()
            false
        }
    }

3. 修改系统语言

我们要实现在 APP 内修改系统语言,并且系统语言更改后,APP 的语言会随之改变,且无需重启 APP。OK,要实现这个功能,我用的是 Java 反射。通过查资料,发现 6.0 以前和 6.0 以后的反射代码会略有不同,下面的代码对切换系统语言做了一个简单的封装,可以实现在 APP 内修改系统语言,即使系统重启也会生效。

package com.xzy.syssettings.utils

import android.app.Activity
import android.app.backup.BackupManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import android.os.LocaleList
import android.widget.Toast
import com.xzy.syssettings.MainActivity2
import com.xzy.syssettings.language.LanguageUtil
import com.xzy.syssettings.language.Sp
import java.lang.Exception
import java.lang.reflect.Method
import java.util.Locale

/**
 *
 * @author :created by xzy.
 * @date :2021/10/28
 */
object LanguageUtil {
    /**
     * 这个方法不需要系统签名
     * 经过测试:android 8.0 以下的版本需要更新 configuration 和 resources,
     * android 8.0 以上只需要将当前的语言环境写入 Sp 文件即可。
     * 测试机型 android4.4、android6.0、android7.0、android7.1、android8.1
     * 然后,重新创建当前页面。
     * @param language
     */
    fun changeAppLanguage(language: String?, activity: Activity) {
        // 版本低于 android 8.0 不执行该方法
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // 注意,这里的 context 不能传 Application 的 context
            LanguageUtil.changeAppLanguage(activity, language!!)
        }
        Sp.put("language", language!!)
        // 不同的版本,使用不同的重启方式,达到最好的效果
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
            // 6.0 以及以下版本,使用这种方式,并给 activity 添加启动动画效果,可以规避黑屏和闪烁问题
            val intent = Intent(activity, MainActivity2::class.java)
            // intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
            activity.startActivity(intent)
            activity.finish()
        } else {
            // 6.0 以上系统直接调用重新创建函数,可以达到无缝切换的效果
            activity.recreate()
        }
    }

    /**
     * 这个方法需要系统签名
     * */
    fun changeSystemLanguage(locale: Locale?, context: Context) {
        if (locale != null) {
            try {
                val classActivityManagerNative = Class.forName("android.app.ActivityManagerNative")
                val getDefault: Method = classActivityManagerNative.getDeclaredMethod("getDefault")
                val objIActivityManager: Any = getDefault.invoke(classActivityManagerNative)

                val classIActivityManager = Class.forName("android.app.IActivityManager")
                val getConfiguration: Method =
                    classIActivityManager.getDeclaredMethod("getConfiguration")
                val config: Configuration =
                    getConfiguration.invoke(objIActivityManager) as Configuration
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    config.locales = LocaleList(locale)
                } else {
                    config.setLocale(locale)
                }
                val clzConfig = Class
                    .forName("android.content.res.Configuration")
                val userSetLocale = clzConfig
                    .getField("userSetLocale")
                userSetLocale[config] = true
                val clzParams = arrayOf<Class<*>>(
                    Configuration::class.java
                )
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    // 该代码决定是否修改系统语言设置(需要有系统签名和sharedUserId)
                    val updatePersistentConfiguration: Method =
                        classIActivityManager.getDeclaredMethod(
                            "updatePersistentConfiguration",
                            *clzParams
                        )
                    updatePersistentConfiguration.invoke(objIActivityManager, config)
                    BackupManager.dataChanged("com.android.providers.settings")
                } else {
                    // updateConfiguration
                    val configuration = context.resources.configuration
                    // 获取想要切换的语言类型
                    configuration.setLocale(locale)
                    // updateConfiguration
                    val dm = context.resources.displayMetrics
                    context.resources.updateConfiguration(configuration, dm)
                    // 下面的代码决定是否修改系统语言设置(需要有系统签名和sharedUserId)
                    val updateConfiguration: Method =
                        classIActivityManager.getDeclaredMethod(
                            "updateConfiguration",
                            *clzParams
                        )
                    updateConfiguration.invoke(objIActivityManager, config)
                    BackupManager.dataChanged("com.android.providers.settings")
                }

                Toast.makeText(
                    context,
                    "language:" + locale.language + "--country:" + locale.country,
                    Toast.LENGTH_SHORT
                ).show()
            } catch (exception: Exception) {
                exception.printStackTrace()
            }
        }
    }
}

如果只需要修改 APP 语言,则只需要调用 changeAppLanguage(LanguageType.ENGLISH.language, this) 即可。
如果同时需要修改系统语言,调用方式为:

 changeSystemLanguage(Locale.ENGLISH, this)
 changeAppLanguage(LanguageType.ENGLISH.language, this)

4. 系统重启

由于 App 有系统签名,所以实现系统重启功能比较简单。其中的一种方式是使用 PowerManager 实现。代码如下:

  // 重新启动到 fastboot模式
  val pManager = getSystemService(Context.POWER_SERVICE) as PowerManager
  pManager.reboot("")

5. 源码

以上功能的实现源码点击这里:源码

6. 参考

  1. Android App设置系统时间,语言和时区
  2. Android 切换系统语言功能实现(下)
  3. android获取地区,Android获取语言及地区总结
  4. android多国语言的国家代码
  5. Android6.0和7.0应用层更改系统语言(反射)
  6. 常用时区
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值