This guide provides step-by-step instructions for integrating Web2Wave quizzes and paywalls into your mobile applications using our native SDKs. Web2Wave offers SDKs for iOS (Swift), Android (Kotlin), Android (Java), and Flutter.
Overview
Web2Wave allows you to embed quizzes and paywalls directly into your mobile app using WebView components. The SDKs handle all communication between your app and the Web2Wave web content, including event handling, navigation, and user interactions.
What You'll Need
- A Web2Wave project with at least one quiz or paywall
- Your quiz/paywall URL (format:
https://yourdomain.com/quiz-slugorhttps://yourdomain.com/paywall/paywall-slug) - A mobile development environment set up for your target platform
Getting Your Quiz/Paywall URL
- Navigate to your quiz or paywall editor in the Web2Wave dashboard
- Click on the Publish button dropdown menu
- Select Embed into mobile app
- Copy the URL displayed in the modal (e.g.,
https://yourdomain.com/quiz-slug)
Quick Links to SDKs
- iOS (Swift) SDK - Native iOS integration using Swift
- Android (Kotlin) SDK - Native Android integration using Kotlin
- Android (Java) SDK - Native Android integration using Java
- Flutter SDK - Cross-platform integration using Flutter
Payment Synchronization with Third-Party Systems
Web2Wave supports synchronizing user payments with third-party subscription management platforms (RevenueCat, Adapty, Qonversion). This ensures that all purchases made through Web2Wave are automatically reflected in your chosen subscription management system.
How It Works
You can pass profile IDs as URL parameters when opening a quiz or paywall. When these parameters are present, Web2Wave will automatically sync all payment transactions for that user to the corresponding third-party system.
Supported Parameters
revenuecat_profile_id- RevenueCat user profile IDadapty_profile_id- Adapty user profile IDqonversion_profile_id- Qonversion user profile ID
Prerequisites
- The corresponding third-party system must be configured in your Project settings in the Web2Wave dashboard
- You need to obtain the profile ID from the third-party SDK before opening the WebView
URL Format
Append the profile ID parameter to your quiz or paywall URL:
https://yourdomain.com/quiz-slug?adapty_profile_id=USER_PROFILE_ID
https://yourdomain.com/paywall-slug?revenuecat_profile_id=USER_PROFILE_ID
https://yourdomain.com/quiz-slug?qonversion_profile_id=USER_PROFILE_ID
You can also combine multiple parameters if needed:
https://yourdomain.com/quiz-slug?adapty_profile_id=USER_ID&revenuecat_profile_id=USER_ID
Important Notes:
- If a user completes a purchase in the WebView, the subscription will be automatically synchronized to the third-party system specified by the profile ID parameter(s).
- Make sure to URL-encode the profile ID if it contains special characters. Most SDKs and URL construction libraries handle this automatically.
- The profile ID must be obtained from the third-party SDK (Adapty, RevenueCat, or Qonversion) before opening the WebView.
iOS (Swift)
Installation
Using Swift Package Manager
- In Xcode, go to File > Add Packages...
- Enter the repository URL:
https://github.com/web2wave/web2wave_swift.git - Select the version (recommended: latest)
- Add the package to your target
Using CocoaPods
Add to your Podfile:
pod 'Web2Wave'Then run:
pod installSetup
- Import the SDK in your Swift file:
import Web2WaveBasic Usage - Opening a Quiz or Paywall
To open a quiz or paywall, you need to:
- Make your view controller conform to the
Web2WaveWebListenerprotocol - Implement the required protocol methods to handle events
- Pass
selfas thedelegateparameter when opening the WebView
Here's a complete example:
import UIKit
import Web2Wave
// 1. Make your view controller conform to Web2WaveWebListener
class ViewController: UIViewController, Web2WaveWebListener {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func openQuizButtonTapped(_ sender: UIButton) {
// Your quiz or paywall URL
var quizURL = "https://yourdomain.com/quiz-slug"
// Optional: Add profile ID for payment synchronization with third-party systems
// Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
if let adaptyProfileID = getAdaptyProfileID() {
// Use URLComponents for proper URL encoding
var components = URLComponents(string: quizURL)
components?.queryItems = [URLQueryItem(name: "adapty_profile_id", value: adaptyProfileID)]
quizURL = components?.url?.absoluteString ?? quizURL
}
// Similarly for RevenueCat:
// if let revenueCatProfileID = getRevenueCatProfileID() {
// var components = URLComponents(string: quizURL)
// components?.queryItems?.append(URLQueryItem(name: "revenuecat_profile_id", value: revenueCatProfileID))
// quizURL = components?.url?.absoluteString ?? quizURL
// }
// Or Qonversion:
// if let qonversionProfileID = getQonversionProfileID() {
// var components = URLComponents(string: quizURL)
// components?.queryItems?.append(URLQueryItem(name: "qonversion_profile_id", value: qonversionProfileID))
// quizURL = components?.url?.absoluteString ?? quizURL
// }
// 2. Open the WebView and pass self as delegate
// The SDK will automatically call your protocol methods when events occur
Web2Wave.shared.showWebView(
currentVC: self,
urlString: quizURL,
topOffset: 0, // Optional: Adjust for status bar/navigation bar
bottomOffset: 0, // Optional: Adjust for tab bar
delegate: self, // Pass self - your view controller implements Web2WaveWebListener
backgroundColor: UIColor.white // Optional: Background color (defaults to white if not provided)
)
}
// MARK: - Web2WaveWebListener Protocol Methods
// Called when any event occurs in the quiz/paywall
func onEvent(event: String, data: [String : Any]?) {
print("Event received: \(event)")
print("Data: \(data ?? [:])")
// Handle specific events
switch event {
case "Quiz finished":
// User completed the quiz
print("User finished the quiz")
case "Subscribe":
// User started a subscription or trial
if let currency = data?["currency"] as? String,
let value = data?["value"] as? String {
print("Subscription started: \(value) \(currency)")
}
case "Purchase":
// User completed a purchase
if let currency = data?["currency"] as? String,
let value = data?["value"] as? String {
print("Purchase completed: \(value) \(currency)")
}
case "InitiateCheckout":
// User initiated checkout process
print("Checkout initiated")
case "CompleteRegistration":
// User reached the paywall page
print("User reached paywall")
case "AddPaymentInfo":
// User submitted payment information
print("Payment info added")
default:
// Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
print("Other event: \(event)")
break
}
}
// Called when the quiz is completed
func onQuizFinished(data: [String : Any]?) {
print("Quiz finished!")
print("Result data: \(data ?? [:])")
// Close the WebView
Web2Wave.shared.closeWebView(currentVC: self)
// Handle quiz completion (e.g., navigate to results screen)
handleQuizCompletion(data: data)
}
// Called when the WebView should be closed
func onClose(data: [String : Any]?) {
print("WebView closed")
print("Data: \(data ?? [:])")
// Close the WebView
Web2Wave.shared.closeWebView(currentVC: self)
// Return to previous screen or handle navigation
}
func handleQuizCompletion(data: [String : Any]?) {
// Your custom logic here
// e.g., navigate to results screen, update user properties, etc.
}
}How it works:
- When you pass
delegate: selfinshowWebView, the SDK stores a reference to your view controller - When events occur in the WebView (quiz finished, screen changed, etc.), the SDK automatically calls the corresponding protocol methods (
onQuizFinished,onEvent,onClose) on your delegate - You don't need to manually connect or register the listener—it's all handled automatically when you pass
selfas the delegate
Alternative: Using an Extension
You can also implement the protocol methods in an extension to keep your code organized:
class ViewController: UIViewController {
// ... your view controller code ...
@IBAction func openQuizButtonTapped(_ sender: UIButton) {
var quizURL = "https://yourdomain.com/quiz-slug"
// Optional: Add profile ID for payment synchronization
if let adaptyProfileID = getAdaptyProfileID() {
var components = URLComponents(string: quizURL)
components?.queryItems = [URLQueryItem(name: "adapty_profile_id", value: adaptyProfileID)]
quizURL = components?.url?.absoluteString ?? quizURL
}
Web2Wave.shared.showWebView(
currentVC: self,
urlString: quizURL,
topOffset: 0,
bottomOffset: 0,
delegate: self,
backgroundColor: UIColor.white // Optional: Background color
)
}
}
// Extension to implement Web2WaveWebListener protocol
extension ViewController: Web2WaveWebListener {
func onEvent(event: String, data: [String : Any]?) {
// Handle events
}
func onQuizFinished(data: [String : Any]?) {
// Handle quiz completion
Web2Wave.shared.closeWebView(currentVC: self)
}
func onClose(data: [String : Any]?) {
// Handle close event
Web2Wave.shared.closeWebView(currentVC: self)
}
}Closing the WebView Programmatically
// Close the WebView at any time
Web2Wave.shared.closeWebView(currentVC: self)Android (Kotlin)
Installation
- Add JitPack repository to your project's
settings.gradle.kts:
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}- Add the dependency to your app-level
build.gradle.kts:
dependencies {
implementation("com.github.web2wave:web2wave_kotlin:1.0.1")
}Setup
The SDK is ready to use after adding the dependency. No initialization required for basic WebView functionality.
Basic Usage - Opening a Quiz or Paywall
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.web2wave.Web2Wave
import android.graphics.Color
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Your quiz or paywall URL
var quizURL = "https://yourdomain.com/quiz-slug"
// Optional: Add profile ID for payment synchronization with third-party systems
// Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
val adaptyProfileID = getAdaptyProfileID() // Get from Adapty SDK
if (adaptyProfileID != null) {
// Use Uri.Builder for proper URL encoding
val uri = android.net.Uri.parse(quizURL).buildUpon()
uri.appendQueryParameter("adapty_profile_id", adaptyProfileID)
quizURL = uri.build().toString()
}
// Similarly for RevenueCat:
// val revenueCatProfileID = getRevenueCatProfileID()
// if (revenueCatProfileID != null) {
// val uri = android.net.Uri.parse(quizURL).buildUpon()
// uri.appendQueryParameter("revenuecat_profile_id", revenueCatProfileID)
// quizURL = uri.build().toString()
// }
// Or Qonversion:
// val qonversionProfileID = getQonversionProfileID()
// if (qonversionProfileID != null) {
// val uri = android.net.Uri.parse(quizURL).buildUpon()
// uri.appendQueryParameter("qonversion_profile_id", qonversionProfileID)
// quizURL = uri.build().toString()
// }
// Create event listener
val listener = object : Web2WaveWebListener {
override fun onEvent(event: String, data: Map<String, Any>?) {
println("onEvent: $event, data: $data")
// Handle specific events
when (event) {
"Quiz finished" -> {
// User completed the quiz
println("User finished the quiz")
}
"Subscribe" -> {
// User started a subscription or trial
val currency = data?.get("currency") as? String
val value = data?.get("value") as? String
println("Subscription started: $value $currency")
}
"Purchase" -> {
// User completed a purchase
val currency = data?.get("currency") as? String
val value = data?.get("value") as? String
println("Purchase completed: $value $currency")
}
"InitiateCheckout" -> {
// User initiated checkout process
println("Checkout initiated")
}
"CompleteRegistration" -> {
// User reached the paywall page
println("User reached paywall")
}
"AddPaymentInfo" -> {
// User submitted payment information
println("Payment info added")
}
else -> {
// Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
println("Other event: $event")
}
}
}
override fun onClose(data: Map<String, Any>?) {
println("onClose: data: $data")
// Close the WebView
Web2Wave.closeWebView(supportFragmentManager)
}
override fun onQuizFinished(data: Map<String, Any>?) {
println("onQuizFinished: data: $data")
// Close the WebView
Web2Wave.closeWebView(supportFragmentManager)
// Handle quiz completion
handleQuizCompletion(data)
}
}
// Open the WebView
Web2Wave.showWebView(
fragmentManager = supportFragmentManager,
url = quizURL,
listener = listener,
topOffset = 0, // Optional: Adjust for status bar/toolbar
bottomOffset = 0, // Optional: Adjust for navigation bar
backgroundColor = Color.WHITE // Optional: Background color (defaults to white if not provided)
)
}
private fun handleQuizCompletion(data: Map<String, Any>?) {
// Your custom logic here
}
}Event Handling Interface
The SDK requires implementing Web2WaveWebListener:
val listener = object : Web2WaveWebListener {
override fun onEvent(event: String, data: Map<String, Any>?) {
// Handle events from the quiz/paywall
}
override fun onClose(data: Map<String, Any>?) {
// Called when WebView should be closed
Web2Wave.closeWebView(supportFragmentManager)
}
override fun onQuizFinished(data: Map<String, Any>?) {
// Called when quiz is completed
Web2Wave.closeWebView(supportFragmentManager)
}
}Closing the WebView Programmatically
// Close the WebView at any time
Web2Wave.closeWebView(supportFragmentManager)Android (Java)
Installation
- Add JitPack repository to your project's
build.gradle:
allprojects {
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}- Add the dependency to your app-level
build.gradle:
dependencies {
implementation 'com.github.web2wave:web2wave_java:1.0.0'
}Setup
The SDK is ready to use after adding the dependency. No initialization required for basic WebView functionality.
Basic Usage - Opening a Quiz or Paywall
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.web2wave.sdk.Web2Wave;
import com.web2wave.sdk.Web2WaveWebListener;
import java.util.Map;
import android.graphics.Color;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Your quiz or paywall URL
String quizURL = "https://yourdomain.com/quiz-slug";
// Optional: Add profile ID for payment synchronization with third-party systems
// Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
String adaptyProfileID = getAdaptyProfileID(); // Get from Adapty SDK
if (adaptyProfileID != null) {
// Use Uri.Builder for proper URL encoding
android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
uriBuilder.appendQueryParameter("adapty_profile_id", adaptyProfileID);
quizURL = uriBuilder.build().toString();
}
// Similarly for RevenueCat:
// String revenueCatProfileID = getRevenueCatProfileID();
// if (revenueCatProfileID != null) {
// android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
// uriBuilder.appendQueryParameter("revenuecat_profile_id", revenueCatProfileID);
// quizURL = uriBuilder.build().toString();
// }
// Or Qonversion:
// String qonversionProfileID = getQonversionProfileID();
// if (qonversionProfileID != null) {
// android.net.Uri.Builder uriBuilder = android.net.Uri.parse(quizURL).buildUpon();
// uriBuilder.appendQueryParameter("qonversion_profile_id", qonversionProfileID);
// quizURL = uriBuilder.build().toString();
// }
// Create event listener
Web2WaveWebListener listener = new Web2WaveWebListener() {
@Override
public void onEvent(String event, Map<String, Object> data) {
System.out.println("onEvent: " + event + ", data: " + data);
// Handle specific events
switch (event) {
case "Quiz finished":
// User completed the quiz
System.out.println("User finished the quiz");
break;
case "Subscribe":
// User started a subscription or trial
String currency = (String) data.get("currency");
String value = (String) data.get("value");
System.out.println("Subscription started: " + value + " " + currency);
break;
case "Purchase":
// User completed a purchase
String purchaseCurrency = (String) data.get("currency");
String purchaseValue = (String) data.get("value");
System.out.println("Purchase completed: " + purchaseValue + " " + purchaseCurrency);
break;
case "InitiateCheckout":
// User initiated checkout process
System.out.println("Checkout initiated");
break;
case "CompleteRegistration":
// User reached the paywall page
System.out.println("User reached paywall");
break;
case "AddPaymentInfo":
// User submitted payment information
System.out.println("Payment info added");
break;
default:
// Handle other events (e.g., "Step 0 Welcome", "Answer Question 1", "Paywall click", etc.)
System.out.println("Other event: " + event);
break;
}
}
@Override
public void onClose(Map<String, Object> data) {
System.out.println("onClose: data: " + data);
// Close the WebView
Web2Wave.closeWebView(getSupportFragmentManager());
}
@Override
public void onQuizFinished(Map<String, Object> data) {
System.out.println("onQuizFinished: data: " + data);
// Close the WebView
Web2Wave.closeWebView(getSupportFragmentManager());
// Handle quiz completion
handleQuizCompletion(data);
}
};
// Open the WebView
Web2Wave.showWebView(
getSupportFragmentManager(),
quizURL,
listener,
0, // topOffset - adjust for status bar/toolbar
0, // bottomOffset - adjust for navigation bar
Color.WHITE // backgroundColor - optional (defaults to white if not provided)
);
}
private void handleQuizCompletion(Map<String, Object> data) {
// Your custom logic here
}
}Event Handling
Implement the Web2WaveWebListener interface:
Web2WaveWebListener listener = new Web2WaveWebListener() {
@Override
public void onEvent(String event, Map<String, Object> data) {
// Handle events from the quiz/paywall
}
@Override
public void onClose(Map<String, Object> data) {
// Called when WebView should be closed
Web2Wave.closeWebView(getSupportFragmentManager());
}
@Override
public void onQuizFinished(Map<String, Object> data) {
// Called when quiz is completed
Web2Wave.closeWebView(getSupportFragmentManager());
}
};Closing the WebView Programmatically
// Close the WebView at any time
Web2Wave.closeWebView(getSupportFragmentManager());Flutter
Installation
- Add the Web2Wave package to your
pubspec.yaml:
dependencies:
web2wave:
git:
url: https://github.com/web2wave/web2wave_flutter.git
ref: main- Run:
flutter pub getSetup
- Import the SDK in your Dart file:
import 'package:web2wave/web2wave.dart';Basic Usage - Opening a Quiz or Paywall
import 'package:flutter/material.dart';
import 'package:web2wave/web2wave.dart';
class QuizScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Quiz'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
_openQuiz(context);
},
child: Text('Open Quiz'),
),
),
);
}
void _openQuiz(BuildContext context) async {
// Your quiz or paywall URL
var quizURL = 'https://yourdomain.com/quiz-slug';
// Optional: Add profile ID for payment synchronization with third-party systems
// Replace getAdaptyProfileID() with actual method to get profile ID from Adapty SDK
final adaptyProfileID = await getAdaptyProfileID(); // Get from Adapty SDK
if (adaptyProfileID != null) {
// Use Uri class for proper URL encoding
final uri = Uri.parse(quizURL);
quizURL = uri.replace(queryParameters: {
...uri.queryParameters,
'adapty_profile_id': adaptyProfileID,
}).toString();
}
// Similarly for RevenueCat:
// final revenueCatProfileID = await getRevenueCatProfileID();
// if (revenueCatProfileID != null) {
// final uri = Uri.parse(quizURL);
// quizURL = uri.replace(queryParameters: {
// ...uri.queryParameters,
// 'revenuecat_profile_id': revenueCatProfileID,
// }).toString();
// }
// Or Qonversion:
// final qonversionProfileID = await getQonversionProfileID();
// if (qonversionProfileID != null) {
// final uri = Uri.parse(quizURL);
// quizURL = uri.replace(queryParameters: {
// ...uri.queryParameters,
// 'qonversion_profile_id': qonversionProfileID,
// }).toString();
// }
// Create event listener
final listener = EventListener();
// Open the WebView
Web2Wave.shared.openWebPage(
context: context,
webPageURL: quizURL,
allowBackNavigation: true,
listener: listener,
backgroundColor: Colors.white, // Optional: Background color (defaults to white if not provided)
);
}
}
// Event listener class
class EventListener extends Web2WaveWebListener {
@override
void onEvent({required String event, Map<String, dynamic>? data}) {
print('onEvent: $event, data: $data');
// Handle specific events
switch (event) {
case 'Quiz finished':
// User completed the quiz
print('User finished the quiz');
break;
case 'Subscribe':
// User started a subscription or trial
final currency = data?['currency'];
final value = data?['value'];
print('Subscription started: $value $currency');
break;
case 'Purchase':
// User completed a purchase
final purchaseCurrency = data?['currency'];
final purchaseValue = data?['value'];
print('Purchase completed: $purchaseValue $purchaseCurrency');
break;
case 'InitiateCheckout':
// User initiated checkout process
print('Checkout initiated');
break;
case 'CompleteRegistration':
// User reached the paywall page
print('User reached paywall');
break;
case 'AddPaymentInfo':
// User submitted payment information
print('Payment info added');
break;
default:
// Handle other events (e.g., 'Step 0 Welcome', 'Answer Question 1', 'Paywall click', etc.)
print('Other event: $event');
break;
}
}
@override
void onClose(Map<String, dynamic>? data) {
print('onClose: data: $data');
// Close the WebView
Web2Wave.shared.closeWebPage();
}
@override
void onQuizFinished(Map<String, dynamic>? data) {
print('onQuizFinished: data: $data');
// Close the WebView
Web2Wave.shared.closeWebPage();
// Handle quiz completion
handleQuizCompletion(data);
}
void handleQuizCompletion(Map<String, dynamic>? data) {
// Your custom logic here
}
}Event Handling
Extend the Web2WaveWebListener class:
class EventListener extends Web2WaveWebListener {
@override
void onEvent({required String event, Map<String, dynamic>? data}) {
// Handle events from the quiz/paywall
print('Event: $event');
print('Data: $data');
}
@override
void onClose(Map<String, dynamic>? data) {
// Called when WebView should be closed
Web2Wave.shared.closeWebPage();
}
@override
void onQuizFinished(Map<String, dynamic>? data) {
// Called when quiz is completed
Web2Wave.shared.closeWebPage();
}
}Closing the WebView Programmatically
// Close the WebView at any time
Web2Wave.shared.closeWebPage();Available Events
Web2Wave sends various events during user interactions with quizzes and paywalls. These events are received through the onEvent method of your event listener. Below is a list of common events you can handle:
Quiz Events
Quiz finished- Triggered when the user completes the quizStep {index} {screen_name}- Triggered when a user visits a specific screen (e.g., "Step 0 Welcome", "Step 1 Question")Answer {screen_name}- Triggered when a user answers a question on a specific screen (e.g., "Answer Question 1")
Paywall Events
CompleteRegistration- Triggered when the user reaches the paywall pagePaywall click- Triggered when a user clicks on the paywallPaywall Prices visible- Triggered when paywall prices are displayedPaywall scroll 1- Triggered when a user scrolls on the paywall (1% scrolled)Paywall scroll 50- Triggered when a user scrolls 50% of the paywall
Checkout & Purchase Events
InitiateCheckout- Triggered when a user initiates the checkout processAddPaymentInfo- Triggered when a user submits payment informationSubscribe- Triggered when a user starts a subscription or trial- Properties:
currency(e.g., "USD"),value(e.g., "19.99")
- Properties:
Purchase- Triggered when a user completes a purchase- Properties:
currency(e.g., "USD"),value(e.g., "19.99")
- Properties:
Event Data Structure
Events may include additional properties in the data parameter. Common properties include:
{
"currency": "USD",
"value": "19.99",
"price_id": "price_123",
"subscription_id": "sub_123",
"quiz_id": "quiz_123",
"paywall_id": "paywall_123",
"screen_index": "0",
"screen_name": "Welcome"
}For a complete list of all available events and their properties, refer to the Web2Wave Events Documentation.
Best Practices
1. Thread Safety
- Android: Ensure WebView operations are performed on the main thread
- iOS: Use completion handlers appropriately for UI updates
- Flutter: Use
async/awaitfor async operations
2. Event Data
The data parameter in event callbacks may be null or empty. Always check before accessing:
// Swift example
func onQuizFinished(data: [String : Any]?) {
guard let data = data else { return }
// Use data safely
}3. Memory Management
- Close WebViews when they're no longer needed
- Remove listeners/references when the view is destroyed
- Use weak references for delegates (iOS) or proper lifecycle management (Android)
4. Offsets
Use topOffset and bottomOffset to account for:
- Status bars
- Navigation bars
- Tab bars
- Notches/Dynamic Island (iOS)
- System navigation bars (Android)
Example for iOS with navigation bar:
let topOffset = view.safeAreaInsets.top + navigationController?.navigationBar.frame.height ?? 0
Web2Wave.shared.showWebView(
currentVC: self,
urlString: quizURL,
topOffset: topOffset,
bottomOffset: 0,
delegate: self,
backgroundColor: UIColor.white // Optional: Background color
)5. Testing
- Test with different screen sizes and orientations
- Test on both iOS and Android devices
- Test with and without network connectivity
- Test event callbacks with different quiz/paywall configurations
Troubleshooting
WebView Not Appearing
- Check that the URL is correct and accessible
- Verify internet connectivity
- Check console logs for errors
- Ensure you're calling
showWebView/openWebPageon the main thread
Events Not Firing
- Verify your listener/delegate is properly implemented
- Check that all required methods are implemented
- Ensure the WebView is not blocked by ad blockers or content blockers
Closing Issues
- Ensure you're calling the close method on the correct thread (usually main thread)
- Check that the fragment manager/view controller reference is valid
- Verify lifecycle is properly managed
API Reference Links
- iOS (Swift): https://github.com/web2wave/web2wave_swift
- Android (Kotlin): https://github.com/web2wave/web2wave_kotlin
- Android (Java): https://github.com/web2wave/web2wave_java
- Flutter: https://github.com/web2wave/web2wave_flutter
Additional Resources
- Web2Wave Dashboard: https://app.web2wave.com
- Support: Contact support through your Web2Wave dashboard
- Documentation: Check the README files in each SDK repository for platform-specific details
Examples Summary
Quick Reference
| Platform | Open Quiz/Paywall | Close WebView | Event Listener |
|---|---|---|---|
| iOS (Swift) | Web2Wave.shared.showWebView(...) | Web2Wave.shared.closeWebView(...) | Web2WaveWebListener protocol |
| Android (Kotlin) | Web2Wave.showWebView(...) | Web2Wave.closeWebView(...) | Web2WaveWebListener interface |
| Android (Java) | Web2Wave.showWebView(...) | Web2Wave.closeWebView(...) | Web2WaveWebListener interface |
| Flutter | Web2Wave.shared.openWebPage(...) | Web2Wave.shared.closeWebPage() | Web2WaveWebListener class |
Need Help?
If you encounter any issues or have questions:
- Check the SDK repository README files for detailed API documentation
- Review the console logs for error messages
- Contact Web2Wave support through your dashboard
- Ensure you're using the latest SDK version