GPRS API 变更

从 Android2.1 <API 7>到 Android 4.4 <API 19>

ConnectivityManager

/**
     * 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) {
        }
    }

实际

IConnectivityManager.setMobileDataEnabled(enabled);
IConnectivityManager.getMobileDataEnabled();

setMobileDataEnabled()可以通过反射方式被调用了

final Class<?> conmanClass = Class.forName(context.getSystemService(Context.CONNECTIVITY_SERVICE).getClass().getName());
final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
iConnectivityManagerField.setAccessible(true);
final Object iConnectivityManager = iConnectivityManagerField.get(context.getSystemService(Context.CONNECTIVITY_SERVICE));
final Class<?> iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
final Method[] methods = iConnectivityManagerClass.getDeclaredMethods();
for (final Method method : methods) {
    if (method.toGenericString().contains("set")) {
        Log.i("TESTING", "Method: " + method.getName());
    }
}

Android L以后

即使你有root权限, setMobileDataEnabled() method 也不能被调用,捷径没有了!

ConnectivityManager getMobileDataEnabled存在 setMobileDataEnabled 已经不存在了

IConnectivityManager 中的方法也不存在

Deprecated:
Talk to TelephonyManager directly
Hide:
1291
1292    public boolean  getMobileDataEnabled() {
1293        IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE);
1294        if (b != null) {
1295            try {
1296                ITelephony it = ITelephony.Stub.asInterface(b);
1297                return it.getDataEnabled();
1298            } catch (RemoteException e) { }
1299        }
1300        return false;
1301    }

setMobileDataEnabled 这个方法 TelephonyManager

getDataEnabled

Hide:
3669
3670    @SystemApi
3671    public boolean getDataEnabled(int subId) {
3672        boolean retVal = false;
3673        try {
3674            retVal = getITelephony().getDataEnabled(subId);
3675        } catch (RemoteException e) {
3676            Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
3677        } catch (NullPointerException e) {
3678        }
3679        Log.d(TAG, "getDataEnabled: retVal=" + retVal);
3680        return retVal;
3681    }



Hide:
3646
3647    @SystemApi
3648    public void More ...setDataEnabled(boolean enable) {
3649        setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
3650    }

这个API hide 就算了,可以发射

@SystemApi 我就无语了 对于一般app就哭了

安卓5.0 LOLLIPOP<API 21>之前的判断移动数据是否打开的做法:

/**
     * 反射获得IConnectivityManager实例
     *
     * @param context
     * @return
     */
    private Object getConnectivityManager(Context context) {
        ConnectivityManager conMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        Class<?> conMgrClass = null;
        Object iConMgr = null;
        try {
            conMgrClass = Class.forName(conMgr.getClass().getName());//ConnectivityManager
            Field iConMgrField = conMgrClass.getDeclaredField("mService");//IConnectivityManager
            iConMgrField.setAccessible(true);
            iConMgr = iConMgrField.get(conMgr);//获得ConnectivityManager的IConnectivityManager实例
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return iConMgr;
    }

    private boolean isMobileEnabled(Context context) {
        try {
            Object iConMgr = getConnectivityManager(context);//IConnectivityManager
            Class<?> iConMgrClass = Class.forName(iConMgr.getClass().getName());
            Method getMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("getMobileDataEnabled");
            getMobileDataEnabledMethod.setAccessible(true);
            return (Boolean) getMobileDataEnabledMethod.invoke(getConnectivityManager(context));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }


    private void setValue(Context context, boolean isopen) {
        try {
            Object iConMgr = getConnectivityManager(context);//IConnectivityManager
            Class<?> iConMgrClass = Class.forName(iConMgr.getClass().getName());
            Method setMobileDataEnabledMethod = iConMgrClass.getDeclaredMethod("setMobileDataEnabled", Boolean.class);
            setMobileDataEnabledMethod.setAccessible(true);
            setMobileDataEnabledMethod.invoke(iConMgr, isopen);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断GPRS是否打开
     *
     * @return
     */
    public boolean isOn() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return isMobileDataEnabledFromLollipop(mContext);
        }
        return isMobileEnabled(mContext);
    }


    private boolean isMobileDataEnabledFromLollipop(Context context) {
        boolean state = false;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            state = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 0) == 1;
        }
        return state;
    }

5.0之后可以这样判断网络是否打开

Settings.Global.getInt(context.getContentResolver(), “mobile_data”, 0),

但是没有ROOT权限依然很难主动打开GPRS

setNetworkPreference

ConnectivityManager.setNetworkPreference(ConnectivityManager.TYPE_WIFI);

android 5.0 中 方法还存在 但是 内部实现 删除了

IConnectivityManager 中 方法也删除了

setAcceptUnvalidated 接受未验证网络

下载源码定位到

 /**
     * Informs the system whether it should switch to {@code network} regardless of whether it is
     * validated or not. If {@code accept} is true, and the network was explicitly selected by the
     * user (e.g., by selecting a Wi-Fi network in the Settings app), then the network will become
     * the system default network regardless of any other network that's currently connected. If
     * {@code always} is true, then the choice is remembered, so that the next time the user
     * connects to this network, the system will switch to it.
     *
     * <p>This method requires the caller to hold the permission
     * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}
     *
     * @param network The network to accept.
     * @param accept Whether to accept the network even if unvalidated.
     * @param always Whether to remember this choice in the future.
     *
     * @hide
     */
    public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
        try {
            mService.setAcceptUnvalidated(network, accept, always);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

Settings WifiNoInternetDialog 中使用 只是hide

反射下 发现要求权限 android.permission.CONNECTIVITY_INTERNAL 这个权限恶心了 系统权限

WifiNoInternetDialog

ConnectivityService 系统调用

 if (DBG) log("handlePromptUnvalidated " + network);
        NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);

        // Only prompt if the network is unvalidated and was explicitly selected by the user, and if
        // we haven't already been told to switch to it regardless of whether it validated or not.
        // Also don't prompt on captive portals because we're already prompting the user to sign in.
        if (nai == null || nai.everValidated || nai.everCaptivePortalDetected ||
                !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
            return;
        }

        Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED);
        intent.setData(Uri.fromParts("netId", Integer.toString(network.netId), null));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName("com.android.settings",
                "com.android.settings.wifi.WifiNoInternetDialog");

        PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
        setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);

总结

1 找到强制使用wiifiAPI

1.1 setNetworkPreference 方法 android 5.0 已经删除

失败 接口删除

1.2 强制使用wiifiAPI

 ConnectivityManager.setAcceptUnvalidated(mNetwork, accept, always);
 反射调用失败 要求权限 android.permission.CONNECTIVITY_INTERNAL 这个权限恶心了 系统权限

失败 系统权限

2 关闭手机GPRS

android 5.0 之后 标识为 @SystemApi 一般应用 调用不了

编译系统签名的app

http://gqdy365.iteye.com/blog/2111949 实际商业项目不合适都有自己的签名

失败 系统API

3 使用 提示用户关闭GPRS

3.1 主动 调用 WifiNoInternetDialog 提示用户

系统调用

3.2 APP修改UI提示用户

results matching ""

    No results matching ""