Event Listeners
ParOne emits events based on user interactions. These will allow you to respond to those interactions in your application. These events are also available on the ParOne video tag itself.
Event | Notes |
---|---|
enterFullscreen | Emitted when a user enters fullscreen |
exitFullscreen | Emitted when a user exits fullscreen |
timeupdate | Emitted when the video element emits a timeupdate event. Includes current time of the video. |
videoEnded | Emitted when a video ends |
// Add an EventListener
const player = document.querySelector("parone-video-block")
player.addEventListener("timeupdate", (event) => {
console.log(event.detail.currentTime)
})
player.addEventListener("videoEnded", () => {
// do something
})
WebView Events
ParOne emits events based on user interactions. These will allow you to respond to those interactions in your native application. These events are also available on the ParOne video tag itself.
Event | Notes |
---|---|
enterFullscreen | Emitted when a user enters fullscreen |
exitFullscreen | Emitted when a user exits fullscreen |
10second | Emitted once for every 10 seconds that a user watches of the video |
25percent | Emitted when a user has seen 25% of a video |
75percent | Emitted when a user has seen 75% of a video |
Controlling the player inside a WebView
To control the player in the WebView from native code, you can use our global handlers via webView.evaluateJavaScript()
on both Android and iOS. You will need to add some JS to the WebView to hold a reference to our element on the page, as seen in External Control. You can then wrap the calls to play()
and pause()
in a function that is called via webView.evaluateJavaScript('your_custom_play_wrapper()')
.
Apple iOS
Below is example code for detecting these events. You will want to copy this in the existing component definition.
For additional information see Messaging between WKWebView and Swift | (GitHUB)
import SwiftUI
import WebKit
struct WebView: UIViewControllerRepresentable {
let htmlString: String
func makeUIViewController(context: Context) -> WebViewController {
let viewController = WebViewController()
viewController.loadHTMLString(htmlString)
return viewController
}
func updateUIViewController(_ uiViewController: WebViewController, context: Context) {
uiViewController.loadHTMLString(htmlString)
}
}
class WebViewController: UIViewController {
private lazy var webView: WKWebView = {
let webViewConfig = WKWebViewConfiguration()
webViewConfig.dataDetectorTypes = []
webViewConfig.allowsInlineMediaPlayback = true
webViewConfig.mediaTypesRequiringUserActionForPlayback = []
let webView = WKWebView(frame: .zero, configuration: webViewConfig)
return webView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
// add listener for enterFullscreen
let userCC = webView.configuration.userContentController
userCC.add(Coordinator(), name: "enterFullscreen")
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
func loadHTMLString(_ htmlString: String) {
webView.loadHTMLString(htmlString, baseURL: nil)
}
}
struct ContentView: View {
let htmlString = "<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0'></meta><script src='https://sdk.parone.io/parone.min.js'></script></head><body>This is a video test<br><parone-video-block feed='YOUR_FEED_ID' content-key='CONTENT_KEY'></parone-video-block></html>"
var body: some View {
WebView(htmlString: htmlString)
}
}
class Coordinator: NSObject, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let name = message.name.components(separatedBy: ".").last {
print("Received message: \(name)")
}
}
}
Android
Below is example code for detecting these events. You will want to copy this in the existing component definition.
For additional information see Messaging between WebView and Android.
private const val arg_id = "id"
private const val arg_feed = "feed"
class JavaScriptInterface {
// name of the handler must match name of event
@JavascriptInterface
public void enterFullscreen() {
Toast.makeText(WebViewActivity.this, "Respond to enterFullscreen event", Toast.LENGTH_LONG).show();
}
}
class SingleBlockFragment : Fragment() {
private var contentKey: String = ""
private var feed: String = "Unknown"
private var targetView: FrameLayout? = null
private var contentView: FrameLayout? = null
private var customView: View? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
contentKey = it.getInt(arg_id)
feed = it.getString(arg_feed) ?: "Unknown"
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
contentView = view.findViewById(R.id.mainview);
targetView = view.findViewById(R.id.targetview);
val html = """
<script src='parone.min.js'></script>
<parone-video-block content-key='$this.contentKey' feed='$this.feed'/>
"""
val webView = view.findViewById<WebView>(R.id.webview).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
webChromeClient = object: WebChromeClient() {
override fun onShowCustomView(view: View, callback: CustomViewCallback) {
targetView?.addView(view)
customView = view
contentView?.setVisibility(View.GONE)
targetView?.setVisibility(View.VISIBLE)
targetView?.bringToFront()
}
override fun onHideCustomView() {
customView?.setVisibility(View.GONE)
targetView?.removeView(customView)
customView = null
targetView?.setVisibility(View.GONE)
contentView?.setVisibility(View.VISIBLE)
}
}
webViewClient = WebViewClient()
}
// we expect the interface object to named Android
webView.addJavascriptInterface(new JavaScriptInterface(), "Android");
webView.loadDataWithBaseURL(
"https://sdk.parone.io", html,
"text/html; charset=UTF-8",
"UTF-8", ""
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_single_block, container, false)
}
companion object {
@JvmStatic
fun newInstance(id: Int = 0, feed: String? = null) =
SingleBlockFragment().apply {
arguments = Bundle().apply {
putInt(arg_id, id)
putString(arg_feed, feed)
}
}
}
}
Flutter
In Flutter, you must create a JavaScript channel with the name 'ParOneChannel'
to receive messages. To send data, you can use the same methodology as for Swift/Kotlin.
WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: Set.from([
JavascriptChannel(
name: 'ParOneChannel',
onMessageReceived: (JavascriptMessage message) {
print(message.message);
})
]),
onWebViewCreated: (WebViewController w) {
webViewController = w;
},
)