Android5.0以上系统的移动网络开关

本文介绍了一个在Android5.0及以上版本中实现移动网络开关的解决方案。由于API变更,传统的ConnectivityManager方法不再适用。文章分享了一种通过TelephonyManager反射调用setDataEnabled方法的新途径,并讨论了解决权限问题的方法。

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

Android5.0以上系统的移动网络开关,有需要的朋友可以参考下。

笔者最近遇到一个非常有意思的bug,贴出来和大家分享下。 
那是一个温暖的早晨,阳光晒得人很舒服。一封bug邮件像一片叶子飘到我的邮箱。


一番交流,笔者确认负责的Widget开关在Android5.0以上系统没有作用。相信很多做过移动网络开关的朋友都知道,传统的方法是在ConnectivityManager中通过反射两个方法setMobileDataEnabled和getMobileDataEnabled来控制移动网络开和关的。



    /**
     * Gets the value of the setting for enabling Mobile data.
     *
     * @return Whether mobile data is enabled.
     * @hide
     */
    public boolean getMobileDataEnabled() {
        try {
            return mService.getMobileDataEnabled();
        } catch (RemoteException e) {
            return true;
        }
    }

    /**
     * Sets the persisted value for enabling/disabling Mobile data.
     *
     * @param enabled Whether the mobile data connection should be
     *            used or not.
     * @hide
     */
    public void setMobileDataEnabled(boolean enabled) {
        try {
            mService.setMobileDataEnabled(enabled);
        } catch (RemoteException e) {
        }
    }


但是打开5.0以上的源码,这两个方法已经不存在了。 

推荐一个不错的在线看源码的网站。在线源码网址



此时老大的提醒帮了我,我打开5.0以上代码的TelephonyMananger类尝试通过反射获取setDataEnabled和getDataEnabled类完成操作。 

源码



/** @hide */
    @SystemApi
    public void setDataEnabled(boolean enable) {
        try {
            getITelephony().setDataEnabled(enable);
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#setDataEnabled", e);
        }
    }

    /** @hide */
    @SystemApi
    public boolean getDataEnabled() {
        try {
            return getITelephony().getDataEnabled();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
        }
        return false;
    }


我的反射方法:



public void setMobileDataState(Context cxt, boolean mobileDataEnabled) {
        TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
    try {
        Method setMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
        if (null != setMobileDataEnabledMethod)
        {
            setMobileDataEnabledMethod.invoke(telephonyService, mobileDataEnabled);
        }
    }
    catch (Exception e) {
        LogHelper.v(TAG, "Error setting" + ((InvocationTargetException)e).getTargetException() + telephonyService);
    }
}

public boolean getMobileDataState(Context cxt) {
        TelephonyManager telephonyService = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
    try {
        Method getMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("getDataEnabled");
        if (null != getMobileDataEnabledMethod)
        {
            boolean mobileDataEnabled = (Boolean) getMobileDataEnabledMethod.invoke(telephonyService);
            return mobileDataEnabled;
        }
    }
    catch (Exception e) {
        LogHelper.v(TAG, "Error getting" + ((InvocationTargetException)e).getTargetException() + telephonyService);
    }

    return false;
}


但是报了InvocationTargetException错误。通过:





((InvocationTargetException)e).getTargetException()


方法得知是执行反射执行时发生如下错误:



Error settingjava.lang.SecurityException: Neither user 10240 nor current process has android.permission.MODIFY_PHONE_STATE.android.telephony.TelephonyManager


这个时候老大提醒我把APP移动到system/app下试试。 

几番尝试,仍是同样的结果。



这个时候一个我无意的操作,将APP移动到system/priv-app,竟然成功了。在这个目录下,开关又可以重新工作了。



当然,我们的应用不可能装在这个目录下,只能采取折中的方案。但整个过程还是很开心的,这个bug算是我第一次发现了不同Android版本之间源码的差异,感觉很有意思。希望对大家有所启发。



转载地址:http://www.aichengxu.com/view/63324


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值