Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android5.0以上系統的移動網絡開關

Android5.0以上系統的移動網絡開關

編輯:關於Android編程

筆者最近遇到一個非常有意思的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版本之間源碼的差異,感覺很有意思。希望對大家有所啟發。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved