Skip to content

Commit

Permalink
fix: Catch network connectivity exceptions (#221)
Browse files Browse the repository at this point in the history
* fix: Catch network connectivity exceptions
  • Loading branch information
izaaz authored Aug 21, 2024
1 parent 6a84910 commit 1ed787b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ class AndroidNetworkConnectivityCheckerPlugin : Plugin {
amplitude.configuration.offline = true
}
}
networkListener = AndroidNetworkListener((amplitude.configuration as Configuration).context)
networkListener = AndroidNetworkListener(
(amplitude.configuration as Configuration).context,
amplitude.logger
)
networkListener.setNetworkChangeCallback(networkChangeHandler)
networkListener.startListening()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,33 @@ class AndroidNetworkConnectivityChecker(private val context: Context, private va
return true
}

val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE)
if (cm is ConnectivityManager) {
if (isMarshmallowAndAbove) {
val network = cm.activeNetwork ?: return false
val capabilities = cm.getNetworkCapabilities(network) ?: return false

return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
try {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE)
if (cm is ConnectivityManager) {
if (isMarshmallowAndAbove) {
val network = cm.activeNetwork ?: return false
val capabilities = cm.getNetworkCapabilities(network) ?: return false

return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
} else {
@SuppressLint("MissingPermission")
val networkInfo = cm.activeNetworkInfo
return networkInfo != null && networkInfo.isConnectedOrConnecting
}
} else {
@SuppressLint("MissingPermission")
val networkInfo = cm.activeNetworkInfo
return networkInfo != null && networkInfo.isConnectedOrConnecting
logger.debug("Service is not an instance of ConnectivityManager. Offline mode is not supported")
return true
}
} else {
logger.debug("Service is not an instance of ConnectivityManager. Offline mode is not supported")
} catch (throwable: Throwable) {
// We've seen issues where we see exceptions being thrown by connectivity manager
// which crashes an app. Its safe to ignore these exceptions since we try our best
// to mark a device as offline
// Github Issues:
// https://github.com/amplitude/Amplitude-Kotlin/issues/220
// https://github.com/amplitude/Amplitude-Kotlin/issues/197
logger.warn("Error checking network connectivity: ${throwable.message}")
logger.warn(throwable.stackTraceToString())
return true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import java.lang.IllegalArgumentException
import com.amplitude.common.Logger

class AndroidNetworkListener(private val context: Context) {
class AndroidNetworkListener(private val context: Context, private val logger: Logger) {
private var networkCallback: NetworkChangeCallback? = null
private var networkCallbackForLowerApiLevels: BroadcastReceiver? = null
private var networkCallbackForHigherApiLevels: ConnectivityManager.NetworkCallback? = null
Expand All @@ -28,18 +28,29 @@ class AndroidNetworkListener(private val context: Context) {
}

fun startListening() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setupNetworkCallback()
} else {
setupBroadcastReceiver()
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setupNetworkCallback()
} else {
setupBroadcastReceiver()
}
} catch (throwable: Throwable) {
// We've seen issues where we see exceptions being thrown by connectivity manager
// which crashes an app. Its safe to ignore these exceptions since we try our best
// to mark a device as offline
// Github Issues:
// https://github.com/amplitude/Amplitude-Kotlin/issues/220
// https://github.com/amplitude/Amplitude-Kotlin/issues/197
logger.warn("Error starting network listener: ${throwable.message}")
}
}

@SuppressLint("NewApi", "MissingPermission")
// startListening() checks API level
// ACCESS_NETWORK_STATE permission should be added manually by users to enable this feature
private fun setupNetworkCallback() {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkRequest =
NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
Expand All @@ -56,7 +67,10 @@ class AndroidNetworkListener(private val context: Context) {
}
}

connectivityManager.registerNetworkCallback(networkRequest, networkCallbackForHigherApiLevels!!)
connectivityManager.registerNetworkCallback(
networkRequest,
networkCallbackForHigherApiLevels!!
)
}

private fun setupBroadcastReceiver() {
Expand All @@ -68,7 +82,8 @@ class AndroidNetworkListener(private val context: Context) {
intent: Intent,
) {
if (ConnectivityManager.CONNECTIVITY_ACTION == intent.action) {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork = connectivityManager.activeNetworkInfo
val isConnected = activeNetwork?.isConnectedOrConnecting == true

Expand All @@ -88,15 +103,28 @@ class AndroidNetworkListener(private val context: Context) {
fun stopListening() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
networkCallbackForHigherApiLevels?.let { connectivityManager.unregisterNetworkCallback(it) }
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
networkCallbackForHigherApiLevels?.let {
connectivityManager.unregisterNetworkCallback(
it
)
}
} else {
networkCallbackForLowerApiLevels?.let { context.unregisterReceiver(it) }
}
} catch (e: IllegalArgumentException) {
// callback was already unregistered.
} catch (e: IllegalStateException) {
// shutdown process is in progress and certain operations are not allowed.
} catch (throwable: Throwable) {
// We've seen issues where we see exceptions being thrown by connectivity manager
// which crashes an app. Its safe to ignore these exceptions since we try our best
// to mark a device as offline
// Github Issues:
// https://github.com/amplitude/Amplitude-Kotlin/issues/220
// https://github.com/amplitude/Amplitude-Kotlin/issues/197
logger.warn("Error stopping network listener: ${throwable.message}")
}
}
}

0 comments on commit 1ed787b

Please sign in to comment.