PierfrancescoSoffritti / android-youtube-player

YouTube Player library for Android and Chromecast, stable and customizable.
https://pierfrancescosoffritti.github.io/android-youtube-player/
MIT License
3.4k stars 758 forks source link

Permission for ACCESS_NETWORK_STATE #1023

Open lokeshbhattarai opened 1 year ago

lokeshbhattarai commented 1 year ago

Question / Problem

Any suggestions on handling permission for android.permission.ACCESS_NETWORK_STATE?

Summary

I ran into an issue when running the app on Android 13 device where it complained about not having permission for ACCESS_NETWORK_STATE. I initialize the YouTubePlayerView programmatically and I set handleNetworkEvents to true while I set enableAutomaticInitialization to false.

I could not find any reference to handling permissions in the documentation.


Caused by: java.lang.SecurityException: ConnectivityService: Neither user 10171 nor current process has android.permission.ACCESS_NETWORK_STATE.
                                        at android.os.Parcel.createExceptionOrNull(Parcel.java:3011)
                                        at android.os.Parcel.createException(Parcel.java:2995)
                                        at android.os.Parcel.readException(Parcel.java:2978)
                                        at android.os.Parcel.readException(Parcel.java:2920)
                                        at android.net.IConnectivityManager$Stub$Proxy.requestNetwork(IConnectivityManager.java:2355)
                                        at android.net.ConnectivityManager.sendRequestForNetwork(ConnectivityManager.java:4209)
                                        at android.net.ConnectivityManager.registerDefaultNetworkCallbackForUid(ConnectivityManager.java:4750)
                                        at android.net.ConnectivityManager.registerDefaultNetworkCallback(ConnectivityManager.java:4717)
                                        at android.net.ConnectivityManager.registerDefaultNetworkCallback(ConnectivityManager.java:4691)
                                        at com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.NetworkObserver.doObserveNetwork(NetworkObserver.kt:75)
                                        at com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.NetworkObserver.observeNetwork(NetworkObserver.kt:31)
                                        at com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.LegacyYouTubePlayerView.initialize(LegacyYouTubePlayerView.kt:102)
                                        at com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView.<init>(YouTubePlayerView.kt:90)
                                        at com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView.<init>(YouTubePlayerView.kt:33)

What I've tried

Adding the permission android:name="android.permission.ACCESS_NETWORK_STATE fixes the crash issue. However I use this library in a SDK, so I can't force to have this permission always available. So can you help me understand what would be the consequence of setting handleNetworkEvents to false if I don't have this permission? Is this just about being able to pause/resume the Player when the internet connection changes or is there anything else to this that I should be aware of?

lokeshbhattarai commented 1 year ago

Default values for both enableAutomaticInitialization and handleNetworkEvents are true so when YouTubePlayerView is initialized via constructor, it runs into RunTimeException when permission is missing.

PierfrancescoSoffritti commented 1 year ago

See the documentation.

Edit: Looks like the link is broken, search for "handleNetworkEvents".

lokeshbhattarai commented 1 year ago

From what I understand from the documentation(please correct me if I'm wrong), you need to define YouTubePlayerView in XML even if you want to initialize it programmatically. This is not how I'm doing it. I create the instance programmatically and add the YouTubePlayerView to a ViewGroup programmatically. Here's a snippet to explain what I'm trying to say.

            val container = FrameLayout(context)
            val playerView = YouTubePlayerView(context) // this line fails if there is no android.permission.ACCESS_NETWORK_STATE
            container.addView(playerView)

            playerView.enableAutomaticInitialization = false
            playerView.initialize(youtubeListener,
                true,
                IFramePlayerOptions.default
            )
PierfrancescoSoffritti commented 1 year ago

I have copy-pasted the code snipped you provided and it works for me. Both with handleNetworkEvents set to true and false.

class MainActivity : AppCompatActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val playerView = YouTubePlayerView(this)

    val root = findViewById<ViewGroup>(R.id.root)
    root.addView(playerView)

    playerView.enableAutomaticInitialization = false
    playerView.initialize(object : AbstractYouTubePlayerListener() {
      override fun onReady(youTubePlayer: YouTubePlayer) {
        youTubePlayer.loadOrCueVideo(lifecycle, "6JYIGclVQdw", 0f)
      }
    },
      handleNetworkEvents = true,
      IFramePlayerOptions.default
    )
  }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

</androidx.appcompat.widget.LinearLayoutCompat>
lokeshbhattarai commented 1 year ago

Thanks for looking into it. Appreciate your time.

The issue is reproducible with your code if you add the following to the Manifest.


 <uses-permission
        android:name="android.permission.ACCESS_NETWORK_STATE"
        tools:node="remove" />

While this is trivial, I have to be able to respect the choice of client app using the SDK I'm working on(to reiterate, I use this SDK in a library project that's distributed via Maven). For now, I am checking for permission before I initialize the YouTubePlayerView. I was wondering if there is a way android-youtube-player SDK could handle this internally.

BTW, I didn't realize there was AbstractYouTubePlayerListener. I very much needed this. Thanks for showing the snippet 🙏

PierfrancescoSoffritti commented 1 year ago

Thanks for clarifying, I understand now :)

We need to check if it's possible to define this permission programmatically instead of in the manifest. If so we could define it only if needed.

If it's not possible, maybe we could wrap the code that requires the permission and catch the exception.

Are you going to be able to look into it?

lokeshbhattarai commented 1 year ago

Yes, I will try adding in a PR. I'm occupied with some work at the moment, so give me a couple of weeks.