Don't insta-crash when network permission is missing

Summary:
public

Rename the `ConnectivityModule` to `NetInfoModule` (there's
no need to name things differently in two places). Add exception
handling to the module in case the network permission is missing.

When the permission is missing, throw an actionable error from
all calls to `NetInfo`: http://imgur.com/zVIMxOV

Without this change, the app immediately crashes on startup:
`getCurrentConnectionType` is called from `Activity.onResume`.

Reviewed By: andreicoman11, bestander

Differential Revision: D2749230

fb-gh-sync-id: 1b752d21a8f28ffeaf60a3322cb76f869dc70a14
This commit is contained in:
Martin Konicek 2015-12-11 10:22:37 -08:00 committed by facebook-github-bot-7
parent 4b800e6ce1
commit f168fc335e
2 changed files with 42 additions and 11 deletions

View File

@ -1,4 +1,11 @@
// Copyright 2004-present Facebook. All Rights Reserved. /**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.modules.netinfo; package com.facebook.react.modules.netinfo;
@ -10,6 +17,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.support.v4.net.ConnectivityManagerCompat; import android.support.v4.net.ConnectivityManagerCompat;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener; import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactApplicationContext;
@ -17,25 +25,30 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.common.ReactConstants;
import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import static com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
/** /**
* Module that monitors and provides information about the connectivity state of the device. * Module that monitors and provides information about the connectivity state of the device.
*/ */
public class ConnectivityModule extends ReactContextBaseJavaModule public class NetInfoModule extends ReactContextBaseJavaModule
implements LifecycleEventListener { implements LifecycleEventListener {
private static final String CONNECTION_TYPE_NONE = "NONE"; private static final String CONNECTION_TYPE_NONE = "NONE";
private static final String CONNECTION_TYPE_UNKNOWN = "UNKNOWN"; private static final String CONNECTION_TYPE_UNKNOWN = "UNKNOWN";
private static final String MISSING_PERMISSION_MESSAGE =
"To use NetInfo on Android, add the following to your AndroidManifest.xml:\n" +
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />";
private final ConnectivityManager mConnectivityManager; private final ConnectivityManager mConnectivityManager;
private final ConnectivityManagerCompat mConnectivityManagerCompat; private final ConnectivityManagerCompat mConnectivityManagerCompat;
private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver; private final ConnectivityBroadcastReceiver mConnectivityBroadcastReceiver;
private boolean mNoNetworkPermission = false;
private String mConnectivity = ""; private String mConnectivity = "";
public ConnectivityModule(ReactApplicationContext reactContext) { public NetInfoModule(ReactApplicationContext reactContext) {
super(reactContext); super(reactContext);
mConnectivityManager = mConnectivityManager =
(ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) reactContext.getSystemService(Context.CONNECTIVITY_SERVICE);
@ -69,11 +82,23 @@ public class ConnectivityModule extends ReactContextBaseJavaModule
@ReactMethod @ReactMethod
public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) { public void getCurrentConnectivity(Callback successCallback, Callback errorCallback) {
if (mNoNetworkPermission) {
if (errorCallback == null) {
FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
return;
}
errorCallback.invoke(MISSING_PERMISSION_MESSAGE);
return;
}
successCallback.invoke(createConnectivityEventMap()); successCallback.invoke(createConnectivityEventMap());
} }
@ReactMethod @ReactMethod
public void isConnectionMetered(Callback successCallback) { public void isConnectionMetered(Callback successCallback) {
if (mNoNetworkPermission) {
FLog.e(ReactConstants.TAG, MISSING_PERMISSION_MESSAGE);
return;
}
successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager)); successCallback.invoke(mConnectivityManagerCompat.isActiveNetworkMetered(mConnectivityManager));
} }
@ -98,15 +123,21 @@ public class ConnectivityModule extends ReactContextBaseJavaModule
} }
private String getCurrentConnectionType() { private String getCurrentConnectionType() {
NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo(); try {
if (networkInfo == null || !networkInfo.isConnected()) { NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
return CONNECTION_TYPE_NONE; if (networkInfo == null || !networkInfo.isConnected()) {
} else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) { return CONNECTION_TYPE_NONE;
return networkInfo.getTypeName().toUpperCase(); } else if (ConnectivityManager.isNetworkTypeValid(networkInfo.getType())) {
} else { return networkInfo.getTypeName().toUpperCase();
} else {
return CONNECTION_TYPE_UNKNOWN;
}
} catch (SecurityException e) {
mNoNetworkPermission = true;
return CONNECTION_TYPE_UNKNOWN; return CONNECTION_TYPE_UNKNOWN;
} }
} }
private void sendConnectivityChangedEvent() { private void sendConnectivityChangedEvent() {
getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class) getReactApplicationContext().getJSModule(RCTDeviceEventEmitter.class)
.emit("networkStatusDidChange", createConnectivityEventMap()); .emit("networkStatusDidChange", createConnectivityEventMap());

View File

@ -20,7 +20,7 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.modules.fresco.FrescoModule; import com.facebook.react.modules.fresco.FrescoModule;
import com.facebook.react.modules.intent.IntentModule; import com.facebook.react.modules.intent.IntentModule;
import com.facebook.react.modules.location.LocationModule; import com.facebook.react.modules.location.LocationModule;
import com.facebook.react.modules.netinfo.ConnectivityModule; import com.facebook.react.modules.netinfo.NetInfoModule;
import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.storage.AsyncStorageModule; import com.facebook.react.modules.storage.AsyncStorageModule;
import com.facebook.react.modules.toast.ToastModule; import com.facebook.react.modules.toast.ToastModule;
@ -57,7 +57,7 @@ public class MainReactPackage implements ReactPackage {
new IntentModule(reactContext), new IntentModule(reactContext),
new LocationModule(reactContext), new LocationModule(reactContext),
new NetworkingModule(reactContext), new NetworkingModule(reactContext),
new ConnectivityModule(reactContext), new NetInfoModule(reactContext),
new WebSocketModule(reactContext), new WebSocketModule(reactContext),
new ToastModule(reactContext)); new ToastModule(reactContext));
} }