当前位置: 代码迷 >> Android >> Android5.0之上系统的移动网络开关
  详细解决方案

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

热度:255   发布时间:2016-04-27 23:43:49.0
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版本之间源码的差异,感觉很有意思。希望对大家有所启发。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  相关解决方案