Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android O Preview : ConnectivityManager removed methods are not backward compatible

Precondition and build config: I am trying to build my app with AndroidStudio 2.4 review 5 by setting below build config paramters for Android O perview device, compileSdkVersion 'android-O' buildToolsVersion '25.0.0' compileOptions.encoding = 'ISO-8859-1' minSdkVersion 16 targetSdkVersion 'O' // Enabling multidex support. multiDexEnabled true

Issue Description: My app uses these below deprecated methods of ConnectivityManager class for devices with older version of android. -ConnectivityManager.startUsingNetworkFeature() - ConnectivityManager.stopUsingNetworkFeature() - ConnectivityManager.requestRouteToHost()

When I try to build my app which has these above api, it is giving compile time error as follows,

Error:(626, 48) error: cannot find symbol method startUsingNetworkFeature(int,String) Error:(7393, 27) error: cannot find symbol method stopUsingNetworkFeature(int,String) Error:(69, 36) error: cannot find symbol method requestRouteToHost(int,int)

Ideally these api should not give compile time error for backward compatibity purpose. Please let me know how to resolve these compile time errors.

I can't remove these methods from code as they are required for devices with older android version(less than Android L version)

like image 370
Mallik Avatar asked Apr 12 '17 09:04

Mallik


2 Answers

Make an new android library module in your project. Make sure this library has compileSdkVersion 25. Then put the following class inside the library:

@SuppressWarnings("Deprecation")
public class NetworkFeaturesCompat {
    public static NetworkFeaturesCompat from(final ConnectivityManager cm) {
        return new NetworkFeaturesCompat(cm);
    }

    private final ConnectivityManager mConnectivityManager;

    private NetworkFeaturesCompat(final ConnectivityManager cm) {
        mConnectivityManager = cm;
    }

    public int startUsingNetworkFeature(final int networkType, final String feature) {
        return mConnectivityManager.startUsingNetworkFeature(networkType, feature);
    }

    public int stopUsingNetworkFeature(final int networkType, final String feature) {
        return mConnectivityManager.stopUsingNetworkFeature(networkType, feature);
    }

    public boolean requestRouteToHost(final int networkType, final int hostAddress) {
        return mConnectivityManager.requestRouteToHost(networkType, hostAddress);
    }
}

Now make your main module depend on this library by altering its build.gradle file:

dependencies {
    compile project(":your-new-library-module-name")
}

Build your project.

Now you can use this helper class from your main project.

You may need to add this to your proguard rules (I haven't actually tested this bit):

-dontwarn android.net.ConnectivityManager

Please note that this approach will still throw UnsupportedOperationException on Android 6+.

Why this works?

The original methods are still present in the SDK, they're just hidden from public API in SDK 26. This is why it doesn't crash at run time.

The library module is compiled against SDK 25 where the methods are still part of public API. This is why it doesn't crash at compile time.

Since the whole project is compiled against SDK 26 proguard may complain about missing methods. In that case just ignore the complaint.

like image 140
Eugen Pechanec Avatar answered Sep 21 '22 01:09

Eugen Pechanec


Because I cannot add comments to Antilope's answer, I will correct it here.

It should be method.invoke(connectivityManager, ConnectivityManager.TYPE_MOBILE, "enableHIPRI");

So in general the code looks like:

try{
    java.lang.reflect.Method method = connectivityManager.getClass().getMethod("startUsingNetworkFeature",
    int.class, String.class); 
    resultInt = (int) method.invoke(connectivityManager, ConnectivityManager.TYPE_MOBILE, 
"enableHIPRI");
} catch (Exception e) { 
    //Do something 
}

and

try{
    java.lang.reflect.Method method = connectivityManager.getClass().getMethod("requestRouteToHost", int.class, int.class);
    resultBool = (boolean) method.invoke(connectivityManager, ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
} catch (Exception e) { 
    //Do something 
}

The above works on targetSDK 27

like image 34
Janusz Drobiński Avatar answered Sep 24 '22 01:09

Janusz Drobiński