Skip to content

Latest commit

 

History

History
508 lines (399 loc) · 15.1 KB

File metadata and controls

508 lines (399 loc) · 15.1 KB

Quick Start

  1. Install
    1. Download SDK
    2. Add to your project
  2. Add to project
    1. The View (THNWidget Container)
    2. The Data (THNDataManager)
    3. Add to the MainView
  3. Configure the SDK
    1. What are THN Pages and Why are important?
    2. How to specify the pages in the SDK
  4. Update other THN Data
    1. Google analytics
    2. isUserLoggedIn
    3. DataLayer
  5. Capture promocodes

1. Install SDK

Download the latest Android agent (AAR) from our Android SDK release notes.

Local AAR File Installation (Recommended)

  1. Download the AAR file

    • Navigate to the THN Native SDK releases
    • Download the latest thn-native-sdk-x.x.x.aar file
    • Save it to a location you can easily access
  2. Create libs directory

    mkdir -p app/libs
  3. Copy AAR to your project

    • Copy the downloaded thn-native-sdk-x.x.x.aar file to your app/libs/ directory
    • Rename it to thnnative.aar for simplicity (optional)
  4. Configure Gradle dependencies Add to your app/build.gradle file:

dependencies {
    implementation files("libs/thnnative.aar")
}
  1. Verify installation

Your project structure should look like this:

app/
├── libs/
│   └── thn-native-sdk.aar
├── build.gradle
└── src/
    └── main/
        ├── AndroidManifest.xml
        └── java/kotlin/

Verify AAR Integration

After adding the AAR file, sync your project and verify the integration:

  1. Sync Project: Click "Sync Now" in Android Studio
  2. Clean and Rebuild:
    ./gradlew clean
    ./gradlew build
  3. Verify imports: You should be able to import THN classes:
     import com.thehotelsnetwork.thnnativesdk.*

2. Add and initialise the THN Native SDK

Basic Integration

The THN Native SDK uses a simple WebView-based approach. You can integrate it directly into your layouts and update data as needed.


### Add to Layout

Add the THNWidgetLoader directly to your layout XML:

`activity_main.xml`
```xml
  <?xml version="1.0" encoding="utf-8"?>
  <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <!-- Your main content -->
      <androidx.fragment.app.FragmentContainerView
          android:id="@+id/nav_host_fragment"
          android:name="androidx.navigation.fragment.NavHostFragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          app:defaultNavHost="true"
          app:navGraph="@navigation/nav_graph" />

      <!-- THN Widget Loader -->
      <com.thehotelsnetwork.thnnativesdk.THNWidgetLoader
          android:id="@+id/thn_widget_loader"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />

  </FrameLayout>

Initialize in Activity

Configure the widget in your Activity:

MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.thehotelsnetwork.thnnativesdk.THNWidgetLoader
import com.thehotelsnetwork.thnnativesdk.THNData
import com.thehotelsnetwork.thnnativesdk.THNPageName

class MainActivity : AppCompatActivity() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

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

        // Initialize THN Widget Loader
        thnWidgetLoader = findViewById(R.id.thn_widget_loader)
        thnWidgetLoader.configure(
            showDebug = true,
            data = THNData(
                propertyId = "1159354",
                pageName = THNPageName.INDEX,
                languageCode = "EN",
                currencyCode = "USD",
            ),
            onPromocodeReceived = { promocodes ->
                // Handle promocodes received
                promocodes.forEach { promocode ->
                    println("Debug: Promocode received: $promocode")
                    // Apply promocode to your booking flow
                }
            }
        )

        // Load initial data
        updateTHNData()
    }

    private fun updateTHNData() {
        val data = THNData(
            propertyId = "1234567", // THN Property ID
            pageName = THNPageName.INDEX,
            languageCode = "EN",
            currencyCode = "USD"
        )

        thnWidgetLoader.updateData(data)
    }
}

3. Configure the SDK

What are THN Pages and Why are important?

With THNPages we will share the actual view type between the native app and the SDK to enable identify which widget should show. THN Personalization widgets are linked to a property and a THNPage. It's necessary to indicate to the SDK which page of the native application we are on so it can evaluate which widgets need to be displayed.

Not all room types are mandatory, define and use the ones your application needs.

There are different types of pages according to their meaning for the SDK:

These parameters are mutually exclusive and account ref takes priority over property id.

Index Page

Index This is usually the initial page of the application or that of a specific hotel if your application includes all those in the chain.

  • propertyId - The THN property ID that identifies the hotel
  • accountRef - The THN account REF that identifies a chain

These parameters are mutually exclusive and account ref takes priority over property id.

HomeFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.thehotelsnetwork.thnnativesdk.*

class HomeFragment : Fragment() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        thnWidgetLoader = view.findViewById(R.id.thn_widget_loader)
        updateTHNData()
    }

    private fun updateTHNData() {
        val data = THNData(
            propertyId = "1234567", // THN property ID
            // or set accountRef: ""
            pageName = THNPageName.INDEX,
            languageCode = "EN",
            currencyCode = "USD"
        )

        thnWidgetLoader.updateData(data)
    }
}

Rooms and Rates Page

The users availability search results page where appear the list of the rooms with the rates.

  • Search - Booking search results
  • Results - Search Results resume

RoomsFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.thehotelsnetwork.thnnativesdk.*

class RoomsFragment : Fragment() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_rooms, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        thnWidgetLoader = view.findViewById(R.id.thn_widget_loader)
        updateTHNData()
    }

    private fun updateTHNData() {
        val data = THNData(
            propertyId = "1234567",
            pageName = THNPageName.ROOMS_AND_RATES,
            languageCode = "EN",
            currencyCode = "USD",
            // *Required* Search results data
            search = THNSearch(
                checkIn = "2025-10-01",
                checkOut = "2025-10-02",
                promoCode = null,
                adults = 2,
                children = 1,
                rooms = listOf(
                    THNRoom(
                        adults = 2,
                        name = "Double room with extra bed",
                        type = THNRoomKind.STANDARD,
                        children = 1,
                        prices = listOf(
                            THNPriceOption(
                                name = "Rate name",
                                totalNight = 100.0,
                                breakfast = true,
                                refundable = true
                            )
                            // Include other prices ...
                        )
                    )
                    // Include other Rooms ...
                )
            ),
            // *Required* Results resume data
            results = THNResults(
                availability = true,
                lowestPriceWithTaxes = 121.0 // or lowestPriceWithoutTaxes = 100.0,
            )
            // Include other updated data ...
        )

        thnWidgetLoader.updateData(data)
    }
}

User Registration Page

The view where the user fills in the guest data for the reservation.

UserRegistrationFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.thehotelsnetwork.thnnativesdk.*

class UserRegistrationFragment : Fragment() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_user_registration, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        thnWidgetLoader = view.findViewById(R.id.thn_widget_loader)
        updateTHNData()
    }

    private fun updateTHNData() {
        val data = THNData(
            propertyId = "1234567",
            pageName = THNPageName.USER_REGISTER_PAGE,
            languageCode = "EN",
            currencyCode = "USD"
            // Include other updated data ...
        )

        thnWidgetLoader.updateData(data)
    }
}

Booking Confirmed Page

The view where the user can see the message that their reservation has been confirmed.

  • BookingId - The booking confirmation identifier (LOC, BID, etc)

BookingConfirmedFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.thehotelsnetwork.thnnativesdk.*

class BookingConfirmedFragment : Fragment() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_booking_confirmed, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        thnWidgetLoader = view.findViewById(R.id.thn_widget_loader)
        updateTHNData()
    }

    private fun updateTHNData() {
        val data = THNData(
            propertyId = "1234567",
            pageName = THNPageName.BOOKING_CONFIRMED,
            languageCode = "EN",
            currencyCode = "USD",
            bookingId = "ABC-123" // *Required* The booking confirmation id
            // Include other updated data ...
        )

        thnWidgetLoader.updateData(data)
    }
}

4. Update extra THN Data

Google Analytics

Register events within Google Analytics contain user interactions or activities with specific elements on a web page that are tracked and measured for analytical purposes. In this property you can specify your Google Analytics Tag ID and the SDK will load it.

isUserLogged

If the user is logged in the native app we should specify this property. There may be messages that will only appear if the user is logged in.

dataLayer

Here we can specify other useful data that we can use when setting the targeting rules for messages in THN Personalization.

You can include additional data in your THNData object:

val data = THNData(
    propertyId = "1234567",
    pageName = THNPageName.INDEX,
    languageCode = "EN",
    currencyCode = "USD",
    googleAnalyticsIds = listOf("GA-TRACKING-ID"), // Google analytics IDs
    isUserLogged = false, // Check if logged in the app
    dataLayer = listOf(
        mapOf("userInHouse" to "true"),
        mapOf("userRegistered" to "false")
        // ... add other data needed to target your users
    )
)

5. Capture Promocodes

Some of the THN Personalization messages offer deals and discounts to the user in the form of promocodes. When the SDK detects that a promocode is being applied, THNWidgetLoader will emit an event with that promocode so you can apply the necessary actions in the native application.

Enable Debug Mode

For testing and development, you can enable debug mode:

// Enable debug mode to see widget boundaries and console logs
thnWidgetLoader.setDebugMode(true)

Handle Promocode Events

Set up the promocode callback to capture and handle promocodes:

class MainActivity : AppCompatActivity() {

    private lateinit var thnWidgetLoader: THNWidgetLoader

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

        thnWidgetLoader = findViewById(R.id.thn_widget_loader)

        // -------------------------
        //  Promocodes Event handle
        // -------------------------
        thnWidgetLoader.onPromocodeReceived = { promocodes ->
            // Here we can capture the promocode events and apply them
            // inside the Native app.
            // Multiple promocodes can be received.
            promocodes.forEach { promocodeData ->
                val promocode = promocodeData["code"] as? String
                println("Debug: Promocode received: $promocode")

                // Example: Apply promocode to search
                promocode?.let { applyPromocodeToSearch(it) }
            }
        }

        // Load initial data
        updateTHNData()
    }

    private fun applyPromocodeToSearch(promocode: String) {
        // Get current data and update with new promocode
        val currentData = getCurrentTHNData() // Your method to get current data

        val updatedSearch = currentData.search?.copy(promoCode = promocode)
        val updatedData = currentData.copy(search = updatedSearch)

        // Update the widget with the new data
        thnWidgetLoader.updateData(updatedData)
    }

    private fun getCurrentTHNData(): THNData {
        // Return your current THNData state
        // This could be stored in a ViewModel or other state management solution
        return THNData(
            propertyId = "1234567",
            pageName = THNPageName.ROOMS_AND_RATES,
            languageCode = "EN",
            currencyCode = "USD"
        )
    }
}