Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: iflix/web-playback-android
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.0
Choose a base ref
...
head repository: iflix/web-playback-android
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 8 commits
  • 4 files changed
  • 4 contributors

Commits on Dec 10, 2018

  1. Update README.md

    denizmveli authored Dec 10, 2018
    Copy the full SHA
    d3fb1d8 View commit details

Commits on Dec 21, 2018

  1. Updated documentation

    Deniz Veli committed Dec 21, 2018
    Copy the full SHA
    43ea201 View commit details

Commits on May 21, 2019

  1. Modified embed link path

    Deniz Veli committed May 21, 2019
    Copy the full SHA
    b706bc6 View commit details

Commits on Nov 6, 2019

  1. Fix learnmore link handling

    Deniz Veli committed Nov 6, 2019
    Copy the full SHA
    75dc81a View commit details

Commits on Feb 13, 2020

  1. Hack to show callbacks

    dbrain committed Feb 13, 2020
    Copy the full SHA
    3bd984d View commit details
  2. Copy the full SHA
    bdc3044 View commit details
  3. Enable debug on webview

    dbrain committed Feb 13, 2020
    Copy the full SHA
    2bb6e51 View commit details
  4. Merge pull request #1 from iflix/hack_to_show_callbacks

    Hack to show callbacks
    dbrain authored Feb 13, 2020
    Copy the full SHA
    52d0d3e View commit details
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,53 @@
## Android Web View Playback Lib
## Android Web View Playback

==============================
### Minimum Requirements

For following library contains the iflix Android WebView Player library and example code.
The following details the requirements for embedding webv3 within a webview for an Android app, supporting video playback of DRM encrypted streams.

In order for video playback to work within a webview container, the following minimum requirements must be met

* Android Lollipop and above - this is required because EME with Widevine DRM encryption is only supported in this version and later.
* The application containing the webview must contain some modifications to automatically accept DRM prompts that would otherwise occur in the web browser. See [WebChromeClient](http://developer.android.com/reference/android/webkit/WebChromeClient.html#onPermissionRequest)
* Example code acheiving the above
```
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun onPermissionRequest(request: PermissionRequest?) {
request!!.grant(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID))
}
```
* This is required as iflix streams require Widevine L1.
* Some modifications may be required to the webview to support full screen

---

### Import our reference library


For following library contains the iflix Android WebView Player library and example code. It solves for all of the above requirements.

To use the web view player follow the following.


### 1 - Import the Player library AAR
#### 1 - Import the Player library AAR

Place the AAR file in your apps `lib` directory and import it into the project
`iflix-webplayer-release-v1.0.0.aar`


### 2 - Load the iflix asset data from our API
#### 2 - Load the iflix asset data from our API

In your app load and present the iflix asset data to your users. Directions for API usage are at [developer.iflix.com](http://developer.iflix.com)


### 3 - Start the Player
#### 3 - Start the Player

Start the `IflixPlayerWebViewActivity` passing in the values for `INTENT_IFLIX_ASSET_TYPE` and `INTENT_IFLIX_ASSET_ID`.

`INTENT_IFLIX_ASSET_TYPE` must equal `IFLIX_ASSET_TYPE_MOVIE` OR `IFLIX_ASSET_TYPE_SHOW`. You can determine this from our API.

`INTENT_IFLIX_ASSET_ID` must be the asset ID of the movie or show.

Example code
Example code in Kotlin

```
val intent = Intent(this, IflixPlayerWebViewActivity::class.java)
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ import android.support.v7.app.AppCompatActivity

import iflix.play.webview.player.IflixPlayerWebViewActivity
import iflix.play.webview.player.IflixPlayerWebViewActivity.Companion.IFLIX_ASSET_TYPE_MOVIE
import iflix.play.webview.player.IflixPlayerWebViewActivity.Companion.IFLIX_ASSET_TYPE_SHOW
import iflix.play.webview.player.IflixPlayerWebViewActivity.Companion.INTENT_IFLIX_ASSET_ID
import iflix.play.webview.player.IflixPlayerWebViewActivity.Companion.INTENT_IFLIX_ASSET_TYPE

Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
package iflix.play.webview.player

import android.content.Context
import android.content.pm.ActivityInfo
import android.os.Build
import android.os.Bundle
import android.os.Message
import android.support.annotation.RequiresApi
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.view.ViewGroup
import android.webkit.PermissionRequest
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import android.content.Intent
import android.net.Uri
import android.util.Log
import android.webkit.*
import android.widget.Button
import android.widget.TextView


class IflixPlayerWebViewActivity : AppCompatActivity() {

init {
WebView.setWebContentsDebuggingEnabled(true)
}

private var playing: Boolean = false
private lateinit var magicButton: Button
private lateinit var debugView: TextView
private lateinit var webView: WebView
private lateinit var webChromeClient: VideoEnabledWebChromeClient

@@ -29,11 +41,21 @@ class IflixPlayerWebViewActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)

// force
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)

setContentView(R.layout.activity_webview)

webView = findViewById(R.id.webView)
debugView = findViewById(R.id.debug_view)
magicButton = findViewById(R.id.magic_button)
magicButton.setOnClickListener {
Log.d("MagicButtonDispatch", "MagicButtonDispatch sending " + if (playing) "pause event" else "play event")
webView.evaluateJavascript(if (playing) {
"window.dispatchEvent(new Event('video-pause'));"
} else {
"window.dispatchEvent(new Event('video-play'));"
}) { Log.d("MagicButtonDispatch", "MagicButtonDispatch Result: $it")}
}

// Initialize the VideoEnabledWebChromeClient and set event handlers
val nonVideoLayout = findViewById<View>(R.id.nonVideoLayout)
@@ -68,14 +90,23 @@ class IflixPlayerWebViewActivity : AppCompatActivity() {
settings.mediaPlaybackRequiresUserGesture = false

// include "partner/grab" in the user agent string for tracking
settings.userAgentString = System.getProperty("http.agent") + " partner/grab"
settings.userAgentString = System.getProperty("http.agent") + " partner/webtest"

// WebView settings
webView.fitsSystemWindows = true

webView.webViewClient = object: WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
setUpEventListeners(view ?: return)
}

override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
view.loadUrl(url)
if (url.contains("/embed") && url.contains("iflix.com")) {
view.loadUrl(url)
} else {
view.getContext()?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
}
return true
}
}
@@ -85,6 +116,11 @@ class IflixPlayerWebViewActivity : AppCompatActivity() {
override fun onPermissionRequest(request: PermissionRequest?) {
request!!.grant(arrayOf(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID))
}

override fun onCreateWindow(view: WebView?, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message?): Boolean {
view?.getContext()?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(view.getHitTestResult().extra)))
return false
}
}

// force fullscreen
@@ -96,7 +132,64 @@ class IflixPlayerWebViewActivity : AppCompatActivity() {
val assetType = intent.getStringExtra(INTENT_IFLIX_ASSET_TYPE)
val assetId = intent.getStringExtra(INTENT_IFLIX_ASSET_ID)

webView.loadUrl("https://m.iflix.com/" + assetType + "/" + assetId + "/play")
val url = "https://www.iflix.com/embed/$assetType/$assetId"
webView.loadUrl(url)
bindJavascriptInterface(webView)
}

private fun updateButtonState() {
if (playing) {
magicButton.text = "Pause"
} else {
magicButton.text = "Play"
}
}

private fun setUpEventListeners(webView: WebView) {
webView.evaluateJavascript("""
window.addEventListener('video-isLoaded', function () { iflixCallbacks.isLoaded() });
window.addEventListener('video-isLoading', function () { iflixCallbacks.isLoading() });
window.addEventListener('video-isPlaying', function () { iflixCallbacks.isPlaying() });
window.addEventListener('video-isPaused', function () { iflixCallbacks.isPaused() });
""") {}
}

private fun bindJavascriptInterface(webView: WebView) {
class IflixJavascriptInterface(private val context: Context) {
@JavascriptInterface
fun isLoaded() {
runOnUiThread {
debugView.text = "State: Loaded"
updateButtonState()
}
}

@JavascriptInterface
fun isLoading() {
runOnUiThread {
debugView.text = "State: Loading"
}
}

@JavascriptInterface
fun isPlaying() {
runOnUiThread {
debugView.text = "State: Playing"
playing = true
updateButtonState()
}
}

@JavascriptInterface
fun isPaused() {
runOnUiThread {
debugView.text = "State: Paused"
playing = false
updateButtonState()
}
}
}
webView.addJavascriptInterface(IflixJavascriptInterface(this), "iflixCallbacks")
}

override fun onBackPressed() {
13 changes: 13 additions & 0 deletions player/src/main/res/layout/activity_webview.xml
Original file line number Diff line number Diff line change
@@ -27,4 +27,17 @@

</RelativeLayout>

<TextView
android:id="@+id/debug_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Initialising"
android:padding="5dp" />
<Button
android:id="@+id/magic_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/debug_view"
android:text="Initialising" />

</RelativeLayout>