L’objectif de l’intégration sans SDK sur les applications mobiles Android et iOS est de créer une Webview qui contiendra un code HTML pour afficher au choix un Simple Player ou un Smart Player.
Différentes variables doivent être passées dynamiquement à la Webview afin de bien paramétrer quelques éléments importants, en voici la liste :
- mdtk : permet de définir sur quel site la vidéo a été publiée
- zone : permet de déterminer sur quelle zone du site la vidéo a été publiée
- src : permet de définir l’ID de la vidéo à jouer (Simple Player uniquement)
- search : permet de définir les termes qui vont alimenter la recherche contextuelle (Smart Player uniquement)
- tagparam / tagparamdecoded : permet de nous communiquer des paramètres publicitaires facultatifs
- ⚠️ urlfacebook : permet de définir l’URL correspondant à l’article sur Desktop (URL referrer)
- ⚠️ gdprconsentstring : permet de nous communiquer la chaîne de consentement RGPD de l’utilisateur
⚠️ : Attention, ces paramètres doivent être impérativement renseignés pour que les vidéos puissent être correctement monétisées
Ces paramètres devront alors être passés sous la forme de variables dans le cas des Smart Players ou dans l’URL de l’iframe pour les Simple Players, par exemple :
https://www.ultimedia.com/deliver/generic/iframe/mdtk/01375002/src/pqvp3r/zone/1/showtitle/1/gdprconsentstring/BOj8iv4Oj8iwYAHABAlxCS-AAAAnF7_______9______9uz_Ov_v_f__33e87_9v_l_7_-___u_-3zd4-_1vf99yfm1-7etr3tp_87ues2_Xur__59__3z3_9phPrsk89r633A/idfa/2D2859BC-7FB6-4225-A3E8-EED25341CA93?urlfacebook=http%3A%2F%2Fwww.exemple.com%2Ftitredelarticle&tagparamdecoded=video_app&sa=D&ust=1586938702508000&usg=AOvVaw0EoSE28fXl4HfVg-fQrA4n
A ces différents paramètres il faut également ajouter la “BaseURL” qui doit correspondre à l’URL de base du site Desktop et qui est reprise pour construire la Webview sur Android et iOS.
Exemple sur Android :
dtkWebView.loadDataWithBaseURL("http://www.exemple.com", IFRAME_DIGITEKA, null, null, null);
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
MainActivity.java
final WebView dtkWebView = (WebView) findViewById(R.id.idDtkWebView);
dtkWebView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
dtkWebView.getSettings().setJavaScriptEnabled(true);
dtkWebView.getSettings().setUseWideViewPort(true);
dtkWebView.getSettings().setLoadWithOverviewMode(true);
dtkWebView.getSettings().setDomStorageEnabled(true);
dtkWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);
dtkWebView.setWebViewClient(new WebViewClient());
String IFRAME_DIGITEKA;
IFRAME_DIGITEKA = "<!doctype html><html>" +
"<head>" +
"<meta name='viewport' content='width=device-width, initial-scale=1' id='mvp' />" +
"<link rel='canonical' href='[URL_REFERER]'>" +
"</head>" +
"<body style='margin:0;padding:0;'>" +
"<div style='position:relative;padding-bottom:56.25%;height:0;width:100%;'>" +
"<iframe id=’um_ultimedia_wrapper_iframeUltimedia’
style='position:absolute;top:0;left:0;width:100%;height:100%;' frameborder='0' scrolling='no' marginwidth='0' marginheight='0' hspace='0' vspace='0' allowfullscreen='true' allow='autoplay' src='https://www.ultimedia.com/deliver/generic/iframe/mdtk/[MDTK]/zone/[ZONE]/src/[VIDEO_ID]/showtitle/1/gdprconsentstring/[CONSENT_STRING]/urlfacebook=[URL_REFERER]&tagparam=[TAG_PARAM]' /></div>" +
"</body>" +
"</html>";
dtkWebView.loadDataWithBaseURL("[BASE_URL]", IFRAME_DIGITEKA, null, null, null);
activity_main.xml
<WebView
android:alpha="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/idDtkWebView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
String targetDiv="" +
"<!DOCTYPE html><html>" +
"<head>" +
"<meta name='viewport' content='width=device-width, initial-scale=1' id='mvp' />"+
"<link rel='canonical' href='[URL_REFERER]'>" +
"</head>" +
"<body>" +
"<div id='ultimedia_wrapper'></div>" +
"<script type='text/javascript'>" +
"var ULTIMEDIA_target = 'ultimedia_wrapper';" +
"var ULTIMEDIA_mdtk = '[MDTK]';" +
"var ULTIMEDIA_zone = '[ZONE]';" +
"var ULTIMEDIA_async = 'true';" +
"var ULTIMEDIA_search = '[SEARCH]';" +
"var ULTIMEDIA_gdprconsentstring = '[CONSENT_STRING]';" +
"var scriptURL = 'https://www.ultimedia.com/js/common/smart.js';" +
"var script = document.createElement('script');" +
"script.type = 'text/javascript';" +
"script.src = scriptURL;" +
"var head = document.getElementsByTagName('head')[0];" +
"head.appendChild(script);" +
"</script>" +
"</body>" +
"</html>";
dtkWebView.loadDataWithBaseURL("[BASE_URL]", targetDiv, null, null, null);
Quelques fonctions utiles pour interagir avec le player depuis l’app :
postMessage('play','*');
postMessage(pause,'*');
postMessage(stop','*');
postMessage('mute=0','*'); //Activer le son
postMessage('mute=1','*'); //Désactiver le son
EX:
dtkWebView.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String url) {
dtkWebView.loadUrl("javascript:(function() { " +
"var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');"+
"player.contentWindow.postMessage('play','*');"+
"})()");
}
});
Le mode full screen est désactivé par défaut sur Android.
Pour mettre la vidéo en mode full screen, on est obligé d'ajouter des codes suivants dans le fichier MainActivity.java
Ici le objet dtkWebView est webview crée pour notre player
package com.example.digitekademoapp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.FrameLayout;
public class MainActivity extends AppCompatActivity {
private int savedScrollPosition = 0;
private WebView dtkWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dtkWebView = (WebView) findViewById(R.id.idDtkWebView);
dtkWebView.getSettings().setJavaScriptEnabled(true);
dtkWebView.getSettings().setAppCacheEnabled(false);
dtkWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
dtkWebView.loadUrl("https://mockup.digiteka.com/scroll_to_play_android.html");
dtkWebView.setWebChromeClient(new MyChrome());
}
/***************** ACTIVATE FULL SCREEN **********************/
private class MyChrome extends WebChromeClient {
private View mCustomView;
private WebChromeClient.CustomViewCallback mCustomViewCallback;
protected FrameLayout mFullscreenContainer;
private int mOriginalOrientation;
private int mOriginalSystemUiVisibility;
public void onHideCustomView()
{
((FrameLayout)getWindow().getDecorView()).removeView(this.mCustomView);
this.mCustomView = null;
getWindow().getDecorView().setSystemUiVisibility(this.mOriginalSystemUiVisibility);
setRequestedOrientation(this.mOriginalOrientation);
this.mCustomViewCallback.onCustomViewHidden();
this.mCustomViewCallback = null;
// Restore the saved scroll position
dtkWebView.post(new Runnable() {
@Override
public void run() {
dtkWebView.scrollTo(0, savedScrollPosition);
}
});
}
public void onShowCustomView(View paramView, WebChromeClient.CustomViewCallback paramCustomViewCallback)
{
if (this.mCustomView != null)
{
onHideCustomView();
return;
}
// Save the current scroll position
savedScrollPosition = dtkWebView.getScrollY();
this.mCustomView = paramView;
this.mOriginalSystemUiVisibility = getWindow().getDecorView().getSystemUiVisibility();
this.mOriginalOrientation = getRequestedOrientation();
this.mCustomViewCallback = paramCustomViewCallback;
((FrameLayout)getWindow().getDecorView()).addView(this.mCustomView, new FrameLayout.LayoutParams(-1, -1));
getWindow().getDecorView().setSystemUiVisibility(3846);
}
}
}
Ajouter ce code pour permettre d’ouvrir un nouvel onglet au click sur la pub
dtkWebView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.getContext().startActivity(
new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
});
new Timer().scheduleAtFixedRate(new TimerTask(){
@Override
public void run(){
if(isVisible(dtkWebView) && !notalreadyplayed){
launchScrollToPlay(dtkWebView);
notalreadyplayed = true;
}
}
},0,500);
public boolean isVisible(final View view) {
final Rect actualPosition = new Rect();
view.getGlobalVisibleRect(actualPosition);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = (size.y - 250);
final Rect screen = new Rect(0, 0, width, height);
return actualPosition.intersect(screen);
}
public void launchScrollToPlay(WebView dtkWebView) {
dtkWebView.post(new Runnable() {
@Override
public void run() {
triggerEvent();
}
});
}
public void triggerEvent() {
dtkWebView.loadUrl("javascript:document.getElementById('um_ultimedia_wrapper_iframeUltimedia').contentWindow.postMessage('play','*');");
dtkWebView.loadUrl("javascript:window.addEventListener('message', function (e) { " +
"if (typeof e.data == 'string' && e.data == 'event=ready') {" +
"document.getElementById('um_ultimedia_wrapper_iframeUltimedia').contentWindow.postMessage('play','*');" +
"}" +
"}, false);"
);
}
PS : Ne pas utiliser l’interface builder pour effectuer cette configuration
3. Charger le contenu de la WKWebView idéalement avec l’URL de la vidéo
let webViewConfiguration = WKWebViewConfiguration()
if #available(iOS 10.0, *) {
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
} else {
webViewConfiguration.requiresUserActionForMediaPlayback = false
}
webViewConfiguration.allowsInlineMediaPlayback = true
webViewConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = true
webViewConfiguration.preferences.javaScriptEnabled = true
webViewConfiguration.
webView = WKWebView(frame: .zero , configuration: webViewConfiguration)
let htmlString = <!doctype html><html>" +
"<head>" +
"<meta name='viewport' content='width=device-width, initial-scale=1' id='mvp' />" +
"<link rel='canonical' href='[URL_REFERER]'>" +
"</head>" +
"<body style='margin:0;padding:0;'>" +
"<div style='position:relative;padding-bottom:56.25%;height:0;width:100%;'>" +
"<iframe id=’um_ultimedia_wrapper_iframeUltimedia’
style='position:absolute;top:0;left:0;width:100%;height:100%;' frameborder='0' scrolling='no' marginwidth='0' marginheight='0' hspace='0' vspace='0' allowfullscreen='true' allow='autoplay' src='https://www.ultimedia.com/deliver/generic/iframe/mdtk/[MDTK]/zone/[ZONE]/src/[VIDEO_ID]/showtitle/1/gdprconsentstring/[CONSENT_STRING]/urlfacebook=[URL_REFERER]&tagparam=[TAG_PARAM]' /></div>" +
"</body>" +
"</html>";
webView.loadHTMLString(htmlString, baseURL: URL(string:"[BASE_URL]")
Afin de donner accès aux fonctionnalités de clics, il est nécessaire d’implémenter deux méthodes :
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(WKNavigationActionPolicy.allow)
}
public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard let url: URL = navigationAction.request.url, let urlScheme = url.scheme else { return nil }
if (urlScheme == "http" || urlScheme == "https") {
UIApplication.shared.openURL(url)
return nil
}
return nil
}
1. Reprendre l’entière configuration nécessaire de la WebView sur l’exemple de l’intégration unitaire.
La page appelée ou le code HTML chargé dans la WebView doit posséder une div dont l’ID est “ultimedia_wrapper”.
let webViewConfiguration = WKWebViewConfiguration()
if #available(iOS 10.0, *) {
webViewConfiguration.mediaTypesRequiringUserActionForPlayback = []
} else {
webViewConfiguration.requiresUserActionForMediaPlayback = false
}
webViewConfiguration.allowsInlineMediaPlayback = true
webViewConfiguration.preferences.javaScriptCanOpenWindowsAutomatically = true
webViewConfiguration.preferences.javaScriptEnabled = true
webView = WKWebView(frame: .zero , configuration: webViewConfiguration)
2. Définir la commande JavaScript d’insertion du Player
3. Injecter le Smart Player dans cette div à l’aide de la commande créée, une fois la page totalement chargée
let insertCommand = "javascript:(function() { " +
"var element = document.getElementById('ultimedia_wrapper');" +
"ULTIMEDIA_target = 'ultimedia_wrapper';" + "ULTIMEDIA_mdtk = '01124706';" + "ULTIMEDIA_zone = '18';" + "ULTIMEDIA_async = 'true';" + "ULTIMEDIA_gdprconsentstring = 'CP2UBAAP2UBAAAHABAFRDgCsAP_AAH_AAAAAg1Nf_X__b2_r8_7_f_t0eY1P9_7__';" +
"var scriptURL = 'https://www.ultimedia.com/js/common/smart.js';" +
"var head = document.getElementsByTagName('head')[0];" + "var script = document.createElement('script');" + "script.type = 'text/javascript';" +
"script.src = scriptURL;" +
"script.onload = function() { " +
"};" +
"head.appendChild(script);" +
"})()"
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript(insertCommand, completionHandler: nil)
Afin de donner accès aux fonctionnalités de clics, il est nécessaire d’implémenter deux méthodes :
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(WKNavigationActionPolicy.allow)
}
public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard let url: URL = navigationAction.request.url, let urlScheme = url.scheme else { return nil }
if (urlScheme == "http" || urlScheme == "https") {
UIApplication.shared.openURL(url)
return nil
}
return nil
}
Quelques fonctions utiles pour interagir avec le player depuis l’app (sur des boutons connectés en @IBAction au controller via le Main.Storyboard) :
@IBAction func playButtonTapped(_ sender: Any) {
let playCommand = "var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');" + "player.contentWindow.postMessage('play','*');"
webView.evaluateJavaScript(playCommand, completionHandler: nil)
}
@IBAction func pauseButtonTapped(_ sender: Any) {
let pauseCommand = "var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');" + "player.contentWindow.postMessage('pause','*');"
webView.evaluateJavaScript(pauseCommand, completionHandler: nil)
}
@IBAction func stopButtonTapped(_ sender: Any) {
let stopCommand = "var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');" + "player.contentWindow.postMessage('stop','*');"
webView.evaluateJavaScript(stopCommand, completionHandler: nil)
}
@IBAction func muteButtonTapped(_ sender: Any) {
let muteCommand = "var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');" + "player.contentWindow.postMessage('mute=1','*');"
webView.evaluateJavaScript(muteCommand, completionHandler: nil)
}
@IBAction func unmuteButtonTapped(_ sender: Any) {
let unmuteCommand = "var player = document.getElementById('um_ultimedia_wrapper_iframeUltimedia');" + "player.contentWindow.postMessage('mute=0','*');"
webView.evaluateJavaScript(unmuteCommand, completionHandler: nil)
}
Selon la configuration des Webviews que vous créez pour l'intégration des players sur iOS, vous pouvez observer un problème de duplication du compteur d'avancement de la vidéo :
le souci vient d'un dataDetectorType, à savoir le type "PhoneNumber".
Il faut donc retirer ce dataDetectorType des webviews que vous créez pour intégrer notre player :