Home rails on native devices
Problem description
Some devices like Android, TVOS or Samsung, allow promotion of contents in their home page. They are mostly presented as rails of contents. Selecting one of them allow user to deeplink to your application.
Proposed solution
Common JavaScript part
Dana offers an abstraction layer that will allow you to mutualize this to have native home rails on different platforms.
First of all, you need to create an implementation of AbstractNativePersonalizationService
. Use this implementation to call your back-end and format data to NativeHomeContent
.
import $AbstractNativePersonalizationService from "@AbstractNativePersonalizationService";
import $TimerManager from "@TimerManager";
import $NativeHomeCollection from "@NativeHomeCollection";
import $NativeHomeCategory from "@NativeHomeCategory";
import $NativeHomeContent from "@NativeHomeContent";
import $ContentTypes from "@ContentTypes";
import $ColorRangeType from "@ColorRangeType";
import $NativeHomeCollectionLayout from "@NativeHomeCollectionLayout";
import $ImageConst from "@ImageConst";
/**
*
* @name MyNativePersonalizationService
* @class
* @extends AbstractNativePersonalizationService
* @implementation
* @property {TimerManager} timerManager Instance of TimerManager
*/
export default $AbstractNativePersonalizationService.declare("MyNativePersonalizationService", {
statics: /** @lends MyNativePersonalizationService */ {
NETWORK_TIMEOUT_SIMULATION: "MyNativePersonalizationService.networkTimeout"
},
properties: {
timerManager: {class: $TimerManager}
},
methods: /** @lends MyNativePersonalizationService.prototype */{
_getHomeRails: function () {
return new Promise((resolve, reject) => {
this.timerManager.setTimeout(_ => {
const collection = new $NativeHomeCollection({
id: "myCollection",
layout: $NativeHomeCollectionLayout.SECTIONED
});
const category1 = new $NativeHomeCategory({
id: "first_rail",
title: "Rail 1",
description: "First rail",
contents: []
});
for (let i = 0; i < 10; i++) {
const now = new Date();
const content = new $NativeHomeContent({
type: $ContentTypes.MOVIE,
id: "" + i,
title: "Item " + i,
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat lorem ac pellentesque mollis. ",
imageUrl: "https://picsum.photos/id/" + i + "/300/200",
aspectRatio: $ImageConst.RATIO_1_1,
genre: "Drama",
duration: 7200,
releaseDate: now.getTime(),
logoUrl: "https://picsum.photos/id/" + (100 + i) + "/200/300"
});
category1.contents.push(content);
}
collection.categories = [category1];
resolve(collection);
}, 2000, this.statics.NETWORK_TIMEOUT_SIMULATION);
});
}
}
});
In app.js
, add explicit import to NativePersonalizationService
.
import $NativePersonalizationService from "@NativePersonalizationService";
Reminder
Explicit import allow Dana to bundle this service even if the class is not imported to be used anywhere in your project. You may need to use // eslint-disable-next-line no-unused-vars
to disable linter for this specific line.
This is all you need to do for JavaScript part. Then, some configuration are required for your target device.
TVOS configuration
To have native rail on home, you should create a Top Shelf extension.
Reminder
You could not configure how often the data are refreshed, it is handled by TVOS.
Top Shelf extension
From Xcode and within your tvOS project, go to the File
menu and select New > Target
.
Under the Application Extensions
, select TV Top Shelf Extension
and tap Next
. Just call it TopShelf
.
Inside your app, a new folder called TopShelf
is created which include file ContentProvider.swift
. Open this file to edit it.
import JscModule
import TVServices
class ContentProvider: TopShelfService {
override func addNamedAttribute(item: TVTopShelfCarouselItem, content: [String: Any]) {
// Write code here if you want to add additional information for caroussel detail mode.
}
}
Deep linking
To make deep link works, you need to define a URL scheme to react to. For example Netflix has chosen ntflx
. Make it as unique to your application as possible.
Add it to the constructor of your ContentProvider
.
class ContentProvider: TopShelfService {
override public init() {
super.init()
self.urlScheme = "myApp"
}
}
Also add it to the info.plist
of you application.
Now, you can launch your TopShelf
target.
Android configuration
To have native rail on home, you should follow the steps below :
Add the implementation in build.gradle
To integrate the home-rails
module into your Android project, you need to add the dependency in your build.gradle
file.
- Open
build.gradle
file. - Add the following line to the dependencies section :
dependencies {
implementation "com.dana.androidtv:home-rails:$project.ext.wtvAndroidtvVersion"
}
Add resources in strings.xml
You need to configure certain resources in the strings.xml
file for the module to work properly. These strings/resources will be used to build deep links needed to access the content.
- Open or create
res/values/strings.xml
file in your project. - Add the following elements :
<ressources>
<string name="host">content</string>
<string name="scheme">ntflx</string>
</ressources>
Explanation :
To make deep link works, you need to define a URL scheme
to react to. For example Netflix has chosen ntflx
. Make it as unique to your application as possible.
host
should be a keyword that reflect the type of content or specific function your are routing to.
With the values provided in the example, the generated URI whould look like this :
ntflx://content/...
Add a job_ids file
The job_ids
file in the res/values directory is used to define unique ID for scheduled job within your module.
- First check if the file
res/values/job_ids.xml
already exists in your projects. If it does not exist, create a next XML file with this name. - Add the
sync_home_rails
definition injob_ids.xml
.
Here an example of what the file might look like :
<resources>
<integer name="sync_home_rails">1</integer> // Replace ID with the desired ID for your job
</resources>
Explanation :
sync_home_rails
: This is the specific job related to home channel/program synchronization.
Precaution
Ensure that the job ids defined in job_ids.xml
are unique within your app. This is important to prevent conflicts.
Dev utility command :
To facilitate development and testing, you can use the following command to manually trigger the synchronization of programs by calling the BroadcastReceiver
:
adb shell am broadcast -a android.media.tv.action.INITIALIZE_PROGRAMS -n <PACKAGE_NAME>/com.dana.androidtv.home_rails.InitProgramsBroadcastReceiver
Reminder
Make sure to replace <PACKAGE_NAME>
with your package name of your project.
Android limitation
Deep-links will be only available in Dana 7.244. Be patient! They are coming !