Guides

Hybrid Integration

Check the following to integrate Saucelive Web and Mobile.

Implementing In-App Bridge Communication


In hybrid apps or web-based apps with native modules, a "bridge" refers to the communication layer between web content and native code.

By using this bridge, web-based code can access and control native device features such as the camera, GPS, or file system. This enables developers to reuse web code across platforms while delivering native-like performance and user experience.


Android Bridge Setup

Project Setup

STEP 1. Create a new project using Android Studio.

STEP 2. Add the following permissions to AndroidManifest.xml for bridge functionality:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

STEP 3. Add a WebView in activity_main.xml:

 <WebView
    android:id="@+id/webview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Creating the Web Page

Create an index.html file in theassetsfolder of the project:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>JS Bridge Example</title>
    </head>
    <body>

        <button onclick="sendMessageToAndroid()">Send Message to Android</button>

        <script>
            function sendMessageToAndroid() {
                AndroidBridge.showMessage("Hello from Web!");
            }
        </script>

    </body>
</html>


WebView Configuration

In MainActivity.java or MainActivity.kt, configure the WebView:

class MainActivity extends AppCompatActivity {

    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = findViewById(R.id.webview);

        // Enable JavaScript
        webView.getSettings().setJavaScriptEnabled(true);

        //Add JavaScript interface
        webView.addJavascriptInterface(new WebAppInterface(this), "sauceflex");

        // Load HTML file from assets
        webView.loadUrl("file:///android_asset/index.html");
    }

    public class WebAppInterface {
        Context mContext;

        WebAppInterface(Context c) {
            mContext = c;
        }

        @JavascriptInterface
        public void showMessage(String message) {
             // Handle the message here
        }
    }
}

MainActivity : AppCompatActivity() {

    private lateinit var webView: WebView

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

        webView = findViewById(R.id.webview)

        // Enable JavaScript
        webView.settings.javaScriptEnabled = true

        // Add JavaScript interface
        webView.addJavascriptInterface(WebAppInterface(this), "sauceflex")

        // Load HTML file from assets
        webView.loadUrl("file:///android_asset/index.html")
    }

    class WebAppInterface(private val mContext: Context) {

        @JavascriptInterface
        fun showMessage(message: String) {
             // Handle the message here
        }
    }
}

Sending Messages from Web to Android

Clicking the button in the web page will call the Android showMessage() method via the sendMessageToAndroid() JavaScript function.

Sending Messages from Android to Web

To call a JavaScript function in the web page from Android, use evaluateJavascript():

webView.evaluateJavascript("alert('Hello from Android!');", null)
// Show PIP button (enable)
myWebView?.evaluateJavascript(
  "(function() { window.dispatchEvent(sauceflexPictureInPictureUse(true)); })();"
) { }
// Hide PIP button (disable)
myWebView?.evaluateJavascript(
  "(function() { window.dispatchEvent(sauceflexPictureInPictureUse(false)); })();"
) { }

Flutter Bridge Setup

This section explains how to use the webview_flutter package to enable communication between a Flutter app and web content.

Add Required Package

Add the webview_flutter package to your pubspec.yaml file:

dependencies:
 flutter:
  sdk: flutter
 webview_flutter: ^3.0.0

Configure the WebView Widget

Use the WebView widget in Flutter to load a web page and establish communication with JavaScript.

// code example
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class WebViewExample extends StatefulWidget {
 @override
 _WebViewExampleState createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State<WebViewExample> {
 final _controller = Completer<WebViewController>();
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(
    title: Text('WebView Example'),
   ),
   body: WebView(
    initialUrl: 'https://yourwebsite.com',
    javascriptMode: JavascriptMode.unrestricted,
    onWebViewCreated: (WebViewController webViewController) {
     _controller.complete(webViewController);
    },
    javascriptChannels: <JavascriptChannel>{
     _createJavascriptChannel(),
    },
   ),
  );
 }
 JavascriptChannel _createJavascriptChannel() {
  return JavascriptChannel(
    name: 'FlutterBridge',
    onMessageReceived: (JavascriptMessage message) {
     print('Message received from web: ${message.message}');
    });
 }
}

Sending Messages from Web Page to Flutter

This section explains the basic method of communication between Flutter and web content.

// code example
function sendMessageToFlutter(message) {
  if (window.FlutterBridge) {
    window.FlutterBridge.postMessage(message);
  }
}

Player Bridge Integration Guide (Web → App Communication)

After implementing the base guide, add platform-specific code as needed.

Add Player Bridge

Android

...
webView.addJavascriptInterface(new WebAppInterface(this), "sauceflex");
...
...
webView.addJavascriptInterface(WebAppInterface(this), "sauceflex")
...

Implement a Functional Bridge for Web-App Communication

Android

public class AndroidBridge {
    private final Context context;
    private final Handler handler = new Handler();

    public AndroidBridge(Context context) {
        this.context = context;
    }

   // Callback when entering the broadcast - automatically triggered upon page load
    @JavascriptInterface
    public void sauceflexEnter() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                //  Add handling code here
            }
        });
    }
    
    // Callback when the broadcast status changes - triggered automatically on state change
    @JavascriptInterface
    public void sauceflexBroadcastStatus(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }

    //Callback when exiting
    @JavascriptInterface
    public void sauceflexMoveExit() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }

    // Callback when logging in
    @JavascriptInterface
    public void sauceflexMoveLogin() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                //  Add handling code here
            }
        });
    }

    //  Callback when a product is clicked
    @JavascriptInterface
    public void sauceflexMoveProduct(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                //  Add handling code here
            }
        });
    }
    
    //Callback when a banner is clicked
    @JavascriptInterface
    public void sauceflexMoveBanner(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }
    
    // Callback when a coupon is clicked
    @JavascriptInterface
    public void sauceflexMoveCoupon(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }
    
    //  Callback when a reward is completed
    @JavascriptInterface
    public void sauceflexMoveReward(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }    

    // Callback when the share button is clicked
    @JavascriptInterface
    public void sauceflexOnShare(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }

    // Callback when the PIP toggle button is clicked
    //(UI elements above the player will be automatically hidden in PIP mode)
    @JavascriptInterface
    public void sauceflexPictureInPicture() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                //  Add handling code here
            }
        });
    }
    
    // Callback for WebView reloading
    @JavascriptInterface
    public void sauceflexWebviewReloading() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                // Add handling code here
            }
        });
    }
}
class AndroidBridge(private val context: Context) {
    private val handler = Handler()
  
    //  Callback when entering the broadcast - automatically triggered when the page loads
    @JavascriptInterface
    fun sauceflexBroadcastStatus() {
        handler.post {
            //  Add handling code here
        }
    }
    
    //  Callback when broadcast status changes - triggered automatically on status updates
    @JavascriptInterface
    fun sauceflexBroadcastStatus(message: String) {
        handler.post {
            // Add handling code here
        }
    }
  
    // Callback when exiting 
    @JavascriptInterface
    fun sauceflexMoveExit() {
        handler.post {
            //  Add handling code here
        }
    }
  
    // Callback when login is triggered
    @JavascriptInterface
    fun sauceflexMoveLogin() {
        handler.post {
            // Add handling code here
        }
    }
  
    //  Callback when a product is clicked
    @JavascriptInterface   
    fun sauceflexMoveProduct(message: String) {
        handler.post {
            // Add handling code here
        }
    }
    
    // Callback when a banner is clicked
    @JavascriptInterface
    fun sauceflexMoveBanner(message: String) {
        handler.post {
            // Add handling code here
        }
    }
    
    //  Callback when a coupon is clicked
    @JavascriptInterface
    fun sauceflexMoveCoupon(message: String) {
        handler.post {
            //  Add handling code here
        }
    }
    
    //  Callback when a reward is completed
    @JavascriptInterface
    fun sauceflexMoveReward(message: String) {
        handler.post {
            // Add handling code here
        }
    }    
  
    // Callback when the share button is clicked
    @JavascriptInterface
    fun sauceflexOnShare(message: String) {
        handler.post {
            //  Add handling code here
        }
    }
  
   // Callback when the PIP toggle button is clicked 
   //(Elements above the player will be hidden automatically in PIP mode)
   @JavascriptInterface   
   fun sauceflexPictureInPicture () {
       handler.post {
           //  Add handling code here
       }
    }
    
    // Callback when the WebView is reloaded
    @JavascriptInterface   
    fun sauceflexWebviewReloading() {
        handler.post {
             // Add handling code here
        }
    }
}

Player Bridge Integration Example (Share)

Android

public class AndroidBridge {
    private Context context;
    private Handler handler;

    // Constructor to initialize the context and handler
    public AndroidBridge(Context context) {
        this.context = context;
        this.handler = new Handler();
    }
  ...
  // sharing
    @JavascriptInterface
    public void sauceflexOnShare(String message) {
        final String finalMessage = message;
        handler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    // message format - Json String
                    JSONObject jsonObject = new JSONObject(message);
                    String shareURL = jsonObject.getString("linkUrl");
                    // If using `shortUrl`, you can replace it with the code below.
                    // String shareURL = jsonObject.getString("shortUrl");
                    Intent intent = new Intent(Intent.ACTION_SEND);
                    intent.setType("text/plain");
                    intent.putExtra(Intent.EXTRA_TEXT, shareURL);
                    context.startActivity(Intent.createChooser(intent, "Share via"));
                } catch (Exception e) {
                    e.printStackTrace();
                    // Error Handling

                }
            }
        });
    }
  ...
}
class AndroidBridge(private val context: Context) {
    private val handler = Handler()
    ...
  
    @JavascriptInterface   // sharing
    fun sauceflexOnShare(message: String) {
        handler.post {
            try {
                // message format - Json String
              	val jsonObject = JSONObject(message)
                val shareURL = jsonObject.getString("linkUrl")
         		    // If using `shortUrl`, you can replace it with the code below.
                // val shareURL = jsonObject.getString("shortUrl")
                val intent = Intent(Intent.ACTION_SEND).apply {
                    type = "text/plain"
                    putExtra(Intent.EXTRA_TEXT, shareURL)
                }
                context.startActivity(Intent.createChooser(intent, "Share via"))
            } catch (e: Exception) {
                e.printStackTrace()
                // Error Handling
            }
        }
    }

   ...
}