@takeoffmedia/react-native-penthera 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +203 -0
- package/android/build.gradle +105 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +51 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/AssetQueueObserver.kt +148 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/EventEmitter.kt +53 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/PentheraModule.kt +104 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/PentheraPackage.kt +16 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/YourPlayerActivity.kt +14 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/DemoLicenseManager.kt +50 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/OfflineVideoEngine.kt +227 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/PentheraContentProvider.kt +17 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/ServiceStarter.kt +65 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/data/Drm.kt +6 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/data/Item.kt +34 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/NotificationFactory.kt +279 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/NotificationType.kt +10 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/notification/ServiceForegroundNotificationProvider.kt +98 -0
- package/android/src/main/java/com/takeoffmediareactnativepenthera/virtuoso/util/Util.kt +22 -0
- package/android/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/android/src/main/res/drawable/small_logo.png +0 -0
- package/android/src/main/res/values/colors.xml +6 -0
- package/android/src/main/res/values/strings.xml +61 -0
- package/android/src/main/res/values/styles.xml +10 -0
- package/android/src/main/res/xml/network_security_config.xml +9 -0
- package/ios/Catalog.swift +30 -0
- package/ios/EventEmitter.swift +53 -0
- package/ios/Penthera-Bridging-Header.h +3 -0
- package/ios/Penthera.m +40 -0
- package/ios/Penthera.swift +384 -0
- package/ios/Penthera.xcodeproj/project.pbxproj +283 -0
- package/ios/Util.swift +16 -0
- package/ios/drm/FairPlayDrmSetup.swift +107 -0
- package/ios/drm/FairPlayLicenseProcessingDelegate.swift +42 -0
- package/lib/commonjs/data/data.json +58 -0
- package/lib/commonjs/hooks/index.js +13 -0
- package/lib/commonjs/hooks/index.js.map +1 -0
- package/lib/commonjs/hooks/usePenthera.js +146 -0
- package/lib/commonjs/hooks/usePenthera.js.map +1 -0
- package/lib/commonjs/index.js +36 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/interface/HomeTypes.js +6 -0
- package/lib/commonjs/interface/HomeTypes.js.map +1 -0
- package/lib/commonjs/interface/Idata.js +2 -0
- package/lib/commonjs/interface/Idata.js.map +1 -0
- package/lib/commonjs/interface/PentheraTypes.js +2 -0
- package/lib/commonjs/interface/PentheraTypes.js.map +1 -0
- package/lib/commonjs/nativeModules/index.js +48 -0
- package/lib/commonjs/nativeModules/index.js.map +1 -0
- package/lib/commonjs/utils/Penthera.js +19 -0
- package/lib/commonjs/utils/Penthera.js.map +1 -0
- package/lib/module/data/data.json +58 -0
- package/lib/module/hooks/index.js +2 -0
- package/lib/module/hooks/index.js.map +1 -0
- package/lib/module/hooks/usePenthera.js +139 -0
- package/lib/module/hooks/usePenthera.js.map +1 -0
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/interface/HomeTypes.js +2 -0
- package/lib/module/interface/HomeTypes.js.map +1 -0
- package/lib/module/interface/Idata.js +2 -0
- package/lib/module/interface/Idata.js.map +1 -0
- package/lib/module/interface/PentheraTypes.js +2 -0
- package/lib/module/interface/PentheraTypes.js.map +1 -0
- package/lib/module/nativeModules/index.js +35 -0
- package/lib/module/nativeModules/index.js.map +1 -0
- package/lib/module/utils/Penthera.js +12 -0
- package/lib/module/utils/Penthera.js.map +1 -0
- package/lib/typescript/hooks/index.d.ts +2 -0
- package/lib/typescript/hooks/index.d.ts.map +1 -0
- package/lib/typescript/hooks/usePenthera.d.ts +19 -0
- package/lib/typescript/hooks/usePenthera.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/interface/HomeTypes.d.ts +15 -0
- package/lib/typescript/interface/HomeTypes.d.ts.map +1 -0
- package/lib/typescript/interface/Idata.d.ts +30 -0
- package/lib/typescript/interface/Idata.d.ts.map +1 -0
- package/lib/typescript/interface/PentheraTypes.d.ts +104 -0
- package/lib/typescript/interface/PentheraTypes.d.ts.map +1 -0
- package/lib/typescript/nativeModules/index.d.ts +9 -0
- package/lib/typescript/nativeModules/index.d.ts.map +1 -0
- package/lib/typescript/utils/Penthera.d.ts +11 -0
- package/lib/typescript/utils/Penthera.d.ts.map +1 -0
- package/package.json +166 -0
- package/src/data/data.json +58 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/usePenthera.ts +160 -0
- package/src/index.tsx +5 -0
- package/src/interface/HomeTypes.ts +16 -0
- package/src/interface/Idata.ts +34 -0
- package/src/interface/PentheraTypes.ts +104 -0
- package/src/nativeModules/index.ts +58 -0
- package/src/utils/Penthera.ts +10 -0
- package/takeoffmedia-react-native-penthera.podspec +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Jonathan Machado
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
|
|
2
|
+
# @takeoffmedia/react-native-penthera
|
|
3
|
+
|
|
4
|
+
This document provide information about the Penthera SDK implementation, we built 2 custom react native wrappers for iOS and Android using the Penthera native SDK
|
|
5
|
+
|
|
6
|
+
## Penthera Cloud
|
|
7
|
+
|
|
8
|
+
Penthera Cloud (backplane), the SDK handles the requests to the Penthera Cloud from the SDK initialization, user login, downloads and so on.
|
|
9
|
+
|
|
10
|
+
## Definition concepts
|
|
11
|
+
|
|
12
|
+
- userID: An unique string identifier of user provided by us, Penthera will use this value to identify and associate any interaction of the SDK with the logged user.
|
|
13
|
+
|
|
14
|
+
- deviceID: An unique string identifier of the device.
|
|
15
|
+
|
|
16
|
+
- asset: Any content downloaded or added to the download quote will be saved as an asset object in Penthera local storage, with an unique string identifier to handle the status of the assets.
|
|
17
|
+
|
|
18
|
+
- VirtuosoHTTPClient: a static http client solution to handle the streaming of the local HLS video format.
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# iOS
|
|
23
|
+
|
|
24
|
+
## requirements
|
|
25
|
+
|
|
26
|
+
- iOS 10 +
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## setup
|
|
30
|
+
|
|
31
|
+
Add the Penthera repository source to the Podfile:
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
source 'https://github.com/penthera/Download2Go-specs.git'
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
Add the framework to the Podfile:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
source 'https://cdn.cocoapods.org/'
|
|
44
|
+
source 'https://github.com/penthera/Download2Go-specs.git'
|
|
45
|
+
|
|
46
|
+
pod 'VirtuosoClientDownloadEngine', :git => 'https://github.com/penthera/Download2Go-ios', :branch => 'master'
|
|
47
|
+
|
|
48
|
+
#ALTERNATIVE - Specify a specific version of Penthera SDK
|
|
49
|
+
#pod 'VirtuosoClientDownloadEngine', '~> 4.2'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Run pod install command.
|
|
53
|
+
|
|
54
|
+
Then add to the AppDelegate.mm the VirtuosoClientDownloadEngine.
|
|
55
|
+
|
|
56
|
+
```Objective-C
|
|
57
|
+
#import <React/RCTAppSetupUtils.h>
|
|
58
|
+
|
|
59
|
+
#import <VirtuosoClientDownloadEngine/VirtuosoClientDownloadEngine.h>
|
|
60
|
+
|
|
61
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
62
|
+
|
|
63
|
+
{
|
|
64
|
+
|
|
65
|
+
//…
|
|
66
|
+
|
|
67
|
+
// Initialize engine and fetch a handle to the singleton instance
|
|
68
|
+
|
|
69
|
+
VirtuosoDownloadEngine* engine = [VirtuosoDownloadEngine instance];
|
|
70
|
+
|
|
71
|
+
// Global “on switch” for downloading
|
|
72
|
+
|
|
73
|
+
[engine setEnabled:YES];
|
|
74
|
+
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Info.plist
|
|
79
|
+
|
|
80
|
+
In your app’s info.plist:
|
|
81
|
+
|
|
82
|
+
- Add “Application Uses Wifi” and set it to YES.
|
|
83
|
+
|
|
84
|
+
- In “Required Background Modes”, add the option “App downloads content in response to push notifications”.
|
|
85
|
+
|
|
86
|
+
- In “Required Background Modes”, add the option “App downloads content from the network”.
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Initialization
|
|
90
|
+
|
|
91
|
+
In our wrapper solution we provided a method to instantiate the SDK, the next parameters are required:
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
userId: logged user identifier
|
|
96
|
+
|
|
97
|
+
backplaneUrl: the url of the Penthera Cloud
|
|
98
|
+
|
|
99
|
+
publicKey: provided by Penthera
|
|
100
|
+
|
|
101
|
+
privateKey: provided by penthera
|
|
102
|
+
|
|
103
|
+
externalDeviceID: Optional deviceID provided by us
|
|
104
|
+
|
|
105
|
+
This method will return a success message in case the initialization is successful otherwise it will return one of the following errors code:
|
|
106
|
+
|
|
107
|
+
| Fruit | Description |
|
|
108
|
+
|-------| -------|
|
|
109
|
+
| PENTHERA_ENGINE_AREADY_STARTED | Virtuoso is already started. |
|
|
110
|
+
| PENTHERA_ENGINE_NO_BACKPLANE | Virtuoso started up, but couldn’t connect to the Cloud. |
|
|
111
|
+
| PENTHERA_ENGINE_INVALID_OPTIONS | Wrong parameters |
|
|
112
|
+
| PENTHERA_ENGINE_METHOD_IS_DEPRECATED | Error changing the user account. |
|
|
113
|
+
| PENTHERA_ENGINE_INTERNAL_EXCEPTION | Virtuoso exception. |
|
|
114
|
+
| PENTHERA_ENGINE_DATA_MIGRATION_ERROR | Error in the core data. |
|
|
115
|
+
| PENTHERA_ENGINE_UNKNOWN_ERROR | Error |
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
## Get download files
|
|
119
|
+
|
|
120
|
+
This method will return an array object with all the downloaded or pending to download assets with this json format:
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
[{
|
|
127
|
+
"assetID": "",
|
|
128
|
+
"isDownloaded": true,
|
|
129
|
+
"thumbnail": ""
|
|
130
|
+
}]
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
## Get asset
|
|
137
|
+
|
|
138
|
+
This method will return the basic information of the asset, it requires an assetID to search within the database of the downloaded files, In case of success it will return a json object with this format:
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
{
|
|
142
|
+
"assetID": "",
|
|
143
|
+
"isDownloaded": true,
|
|
144
|
+
"thumbnail": "",
|
|
145
|
+
"streamURL": "",
|
|
146
|
+
"thumbnailTrack": "",
|
|
147
|
+
"subtitle": ""
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
## Download asset
|
|
153
|
+
|
|
154
|
+
This method will add to the download quote an asset, it required:
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
assetID: unique content identifier
|
|
158
|
+
title: title of the content
|
|
159
|
+
streamURL:
|
|
160
|
+
thumbnailURL:
|
|
161
|
+
thumbnailTrackURL:
|
|
162
|
+
subtitleURL:
|
|
163
|
+
|
|
164
|
+
It will return an success message or an error code
|
|
165
|
+
|
|
166
|
+
## Play asset
|
|
167
|
+
|
|
168
|
+
This method will allow you to playback a downloaded content, just need to send the assetId as parameter and it will return a json object with asset information:
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
## Delete asset
|
|
172
|
+
|
|
173
|
+
Delete a specific asset from the Penthera database, the assetID is required.
|
|
174
|
+
|
|
175
|
+
## Delete all assets
|
|
176
|
+
|
|
177
|
+
Delete all the downloaded or pending to download assets in the Penthera database.
|
|
178
|
+
|
|
179
|
+
## DRM
|
|
180
|
+
|
|
181
|
+
In case that the assets required DRM support, Penthera support the FairPlay playback offline, first we have to set the VirtuosoLicenseManager, this class will allow us to:
|
|
182
|
+
|
|
183
|
+
* Configure the license and certificate
|
|
184
|
+
|
|
185
|
+
* Manually induce the download of an offline license key for an asset,
|
|
186
|
+
|
|
187
|
+
* Manually induce the refresh of a license key,
|
|
188
|
+
|
|
189
|
+
* manually delete a license key from SDK management,
|
|
190
|
+
|
|
191
|
+
* Provide a license key to the SDK for management which you acquired in a custom manner, and
|
|
192
|
+
|
|
193
|
+
* Retrieve the managed license key for an asset, in case you need to manually provide it to a player in
|
|
194
|
+
|
|
195
|
+
* Some custom manner rather than letting the SDK provide it during playback.
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
The VirtuosoLicenseManager instance has 2 functions to set the License and the certificate:
|
|
199
|
+
|
|
200
|
+
- VirtuosoLicenseManager.downloadClientAppCertificate(fromURL: certificateURL, for: .vlm_FairPlay)
|
|
201
|
+
|
|
202
|
+
- VirtuosoLicenseManager.setLicenseServerURL(licenseURL, for: .vlm_FairPlay)
|
|
203
|
+
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
buildscript {
|
|
2
|
+
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
|
|
3
|
+
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["Penthera_kotlinVersion"]
|
|
4
|
+
|
|
5
|
+
repositories {
|
|
6
|
+
google()
|
|
7
|
+
mavenCentral()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
dependencies {
|
|
11
|
+
classpath "com.android.tools.build:gradle:7.2.1"
|
|
12
|
+
// noinspection DifferentKotlinGradleVersion
|
|
13
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def isNewArchitectureEnabled() {
|
|
18
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
apply plugin: "com.android.library"
|
|
22
|
+
apply plugin: "kotlin-android"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
|
|
26
|
+
|
|
27
|
+
if (isNewArchitectureEnabled()) {
|
|
28
|
+
apply plugin: "com.facebook.react"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def getExtOrDefault(name) {
|
|
32
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["Penthera_" + name]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def getExtOrIntegerDefault(name) {
|
|
36
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["Penthera_" + name]).toInteger()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
android {
|
|
40
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
41
|
+
|
|
42
|
+
defaultConfig {
|
|
43
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
44
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
45
|
+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
|
|
46
|
+
}
|
|
47
|
+
buildTypes {
|
|
48
|
+
release {
|
|
49
|
+
minifyEnabled false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
lintOptions {
|
|
54
|
+
disable "GradleCompatible"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
compileOptions {
|
|
58
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
59
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
repositories {
|
|
65
|
+
mavenCentral()
|
|
66
|
+
google()
|
|
67
|
+
//Penthera
|
|
68
|
+
maven { url 'https://clientbuilds.penthera.com/repository/releases/'
|
|
69
|
+
credentials {
|
|
70
|
+
username "britbox"
|
|
71
|
+
password "Br1tB0x"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
maven { url 'https://artifacts.bitmovin.com/artifactory/public-releases' }
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
79
|
+
|
|
80
|
+
dependencies {
|
|
81
|
+
implementation "com.facebook.react:react-native:+"
|
|
82
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
83
|
+
//penthera
|
|
84
|
+
implementation 'com.penthera:cnc-android-sdk-debug:5.3.5'
|
|
85
|
+
implementation 'com.google.code.gson:gson:2.8.6'
|
|
86
|
+
implementation "com.penthera:cnc-android-bitmovin-support:5.3.6-beta"
|
|
87
|
+
|
|
88
|
+
implementation 'com.bitmovin.player:player:3.38.2'
|
|
89
|
+
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
|
|
90
|
+
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
|
91
|
+
|
|
92
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.8.20"
|
|
93
|
+
implementation 'androidx.core:core-ktx:1.10.1'
|
|
94
|
+
implementation 'androidx.appcompat:appcompat:1.6.1'
|
|
95
|
+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
|
96
|
+
implementation project(path: ':bitmovin-player-react-native')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (isNewArchitectureEnabled()) {
|
|
100
|
+
react {
|
|
101
|
+
jsRootDir = file("../src/")
|
|
102
|
+
libraryName = "Penthera"
|
|
103
|
+
codegenJavaPackageName = "com.penthera"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
xmlns:tools="http://schemas.android.com/tools"
|
|
3
|
+
package="com.takeoffmediareactnativepenthera">
|
|
4
|
+
|
|
5
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
6
|
+
|
|
7
|
+
<application
|
|
8
|
+
tools:replace="android:label"
|
|
9
|
+
android:allowBackup="true"
|
|
10
|
+
android:label="@string/app_name"
|
|
11
|
+
android:supportsRtl="true"
|
|
12
|
+
android:theme="@style/AppTheme">
|
|
13
|
+
|
|
14
|
+
<meta-data android:name="com.penthera.virtuososdk.notification.provider.impl" android:value="com.takeoffmediareactnativepenthera.virtuoso.notification.ServiceForegroundNotificationProvider" />
|
|
15
|
+
|
|
16
|
+
<!-- Meta Data to configure license manager for DRM -->
|
|
17
|
+
<meta-data tools:replace="android:value" android:name="com.penthera.virtuososdk.license.manager.impl" android:value="com.takeoffmediareactnativepenthera.virtuoso.DemoLicenseManager"/>
|
|
18
|
+
|
|
19
|
+
<!-- Service Starter -->
|
|
20
|
+
<receiver android:name=".virtuoso.ServiceStarter"
|
|
21
|
+
android:enabled="true"
|
|
22
|
+
android:exported="true"
|
|
23
|
+
android:label="SDKDemoKotlin Service Starter"
|
|
24
|
+
android:directBootAware="true">
|
|
25
|
+
<intent-filter>
|
|
26
|
+
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
27
|
+
<action android:name="android.intent.action.QUICKBOOT_POWERON"/>
|
|
28
|
+
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
|
|
29
|
+
<action android:name="android.intent.action.PACKAGE_REMOVED" />
|
|
30
|
+
<data android:scheme="package"/>
|
|
31
|
+
</intent-filter>
|
|
32
|
+
<intent-filter>
|
|
33
|
+
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
|
34
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
35
|
+
</intent-filter>
|
|
36
|
+
|
|
37
|
+
</receiver>
|
|
38
|
+
|
|
39
|
+
<!-- Catalog Provider -->
|
|
40
|
+
<meta-data
|
|
41
|
+
android:name="com.penthera.virtuososdk.client.pckg"
|
|
42
|
+
android:value="${applicationId}.virtuoso.provider" />
|
|
43
|
+
|
|
44
|
+
<provider
|
|
45
|
+
android:name="com.takeoffmediareactnativepenthera.virtuoso.PentheraContentProvider"
|
|
46
|
+
android:authorities="${applicationId}.virtuoso.provider"
|
|
47
|
+
android:process=":vservice"/>
|
|
48
|
+
|
|
49
|
+
</application>
|
|
50
|
+
|
|
51
|
+
</manifest>
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import com.penthera.common.Common
|
|
5
|
+
import com.penthera.virtuososdk.client.IAsset
|
|
6
|
+
import com.penthera.virtuososdk.client.IAssetManager
|
|
7
|
+
import com.penthera.virtuososdk.client.IIdentifier
|
|
8
|
+
import com.penthera.virtuososdk.client.Observers
|
|
9
|
+
import com.takeoffmediareactnativepenthera.virtuoso.OfflineVideoEngine
|
|
10
|
+
|
|
11
|
+
class AssetQueueObserver(mOfflineVideo : OfflineVideoEngine) : Observers.IQueueObserver {
|
|
12
|
+
|
|
13
|
+
private var lastProgress : Int = -1
|
|
14
|
+
private var mOfflineVideo : OfflineVideoEngine = mOfflineVideo
|
|
15
|
+
|
|
16
|
+
override fun engineStartedDownloadingAsset(aAsset: IIdentifier) {
|
|
17
|
+
lastProgress = -1
|
|
18
|
+
updateItem(aAsset, true)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override fun enginePerformedProgressUpdateDuringDownload(aAsset: IIdentifier) {
|
|
22
|
+
updateItem(aAsset, true)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override fun engineCompletedDownloadingAsset(aAsset: IIdentifier) {
|
|
26
|
+
val updateAsset = aAsset as IAsset
|
|
27
|
+
val assetId = updateAsset.assetId
|
|
28
|
+
updateItem(aAsset, true)
|
|
29
|
+
EventEmitter.sharedInstance.dispatch("penthera", PentheraEvent.DOWNLOAD_COMPLETE, assetId, "")
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
override fun engineEncounteredErrorDownloadingAsset(aAsset: IIdentifier) {
|
|
34
|
+
// The base implementation does nothing. See class documentation.
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun engineUpdatedQueue() {
|
|
38
|
+
// This indicates a change to the download queue - meaning either we added or removed something
|
|
39
|
+
Log.e("MiModulo","<<<<<<<<<<engineUpdatedQueue>>>>>>>>>>>>")
|
|
40
|
+
|
|
41
|
+
val assetManager: IAssetManager = mOfflineVideo.virtuoso!!.assetManager
|
|
42
|
+
val queued = assetManager.queue.size()
|
|
43
|
+
val downloaded = assetManager.downloaded.cursor.count
|
|
44
|
+
val curAsset = mOfflineVideo.asset
|
|
45
|
+
if (curAsset != null && (queued > 0 || downloaded > 0)) {
|
|
46
|
+
val asset = assetManager.get(curAsset.id) as IAsset
|
|
47
|
+
if (asset.downloadStatus != curAsset.downloadStatus) {
|
|
48
|
+
mOfflineVideo.asset = asset
|
|
49
|
+
updateItem(asset, true)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (queued == 0) {
|
|
53
|
+
// The asset has been deleted or downloaded
|
|
54
|
+
Log.e("MiModulo","<<<<<<<<<<Asset deleted>>>>>>>>>>>>")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override fun engineEncounteredErrorParsingAsset(mAssetId: String) {
|
|
59
|
+
Log.e("MiModulo","<<<<<<<<<<engineEncounteredErrorParsingAsset>>>>>>>>>>>>")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
private fun updateItem(aFile: IIdentifier, forceUpdate: Boolean) {
|
|
64
|
+
Log.e("MiModulo","<<<<<<<<<<updateItem>>>>>>>>>>>>")
|
|
65
|
+
|
|
66
|
+
val updateAsset = aFile as IAsset
|
|
67
|
+
val assetId = updateAsset.assetId
|
|
68
|
+
|
|
69
|
+
// Progress is for catalog item
|
|
70
|
+
if (assetId.isNotEmpty() && mOfflineVideo.assetId == assetId) {
|
|
71
|
+
//update our asset status
|
|
72
|
+
// mActivity.runOnUiThread{ updateItemStatus(updateAsset, forceUpdate) }
|
|
73
|
+
//mOfflineVideo { updateItemStatus(updateAsset, forceUpdate) }
|
|
74
|
+
updateItemStatus(updateAsset, forceUpdate)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private fun updateItemStatus(asset: IAsset?, forceUpdate: Boolean) {
|
|
79
|
+
Log.e("MiModulo","<<<<<<<<<<updateItemStatus>>>>>>>>>>>>")
|
|
80
|
+
|
|
81
|
+
asset?.let{
|
|
82
|
+
if(mOfflineVideo.assetId == it.assetId){
|
|
83
|
+
mOfflineVideo.asset = asset
|
|
84
|
+
|
|
85
|
+
var progress = (asset.fractionComplete * 100.0).toInt()
|
|
86
|
+
EventEmitter.sharedInstance.dispatch("penthera", PentheraEvent.PROGRESS_UPDATED, it.assetId, progress.toString())
|
|
87
|
+
// Not a repeated progress -- Keep context switches minimal due to frequency of messages, unless forced
|
|
88
|
+
if (forceUpdate || progress != lastProgress) {
|
|
89
|
+
val assetStatus : String
|
|
90
|
+
val value: String
|
|
91
|
+
when (asset.downloadStatus) {
|
|
92
|
+
|
|
93
|
+
Common.AssetStatus.DOWNLOADING -> {
|
|
94
|
+
assetStatus = "Downloading"
|
|
95
|
+
value = "downloading"
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Common.AssetStatus.DOWNLOAD_COMPLETE -> {
|
|
99
|
+
assetStatus = "Downloading"
|
|
100
|
+
value = "complete"
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Common.AssetStatus.EXPIRED -> {
|
|
104
|
+
assetStatus = "Expired"
|
|
105
|
+
value = "expired"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
Common.AssetStatus.DOWNLOAD_DENIED_ASSET -> {
|
|
109
|
+
assetStatus = "Queued"
|
|
110
|
+
value = "DENIED : MAD"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Common.AssetStatus.DOWNLOAD_DENIED_ACCOUNT -> {
|
|
114
|
+
assetStatus = "Queued"
|
|
115
|
+
value = "DENIED : MDA"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
Common.AssetStatus.DOWNLOAD_DENIED_EXTERNAL_POLICY -> {
|
|
119
|
+
assetStatus = "Queued"
|
|
120
|
+
value = "DENIED : EXT"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
Common.AssetStatus.DOWNLOAD_DENIED_MAX_DEVICE_DOWNLOADS -> {
|
|
124
|
+
assetStatus = "Queued"
|
|
125
|
+
value = "DENIED :MPD"
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Common.AssetStatus.DOWNLOAD_BLOCKED_AWAITING_PERMISSION -> {
|
|
129
|
+
assetStatus = "Queued"
|
|
130
|
+
value = "AWAITING PERMISSION"
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
Common.AssetStatus.DOWNLOAD_DENIED_COPIES -> {
|
|
134
|
+
assetStatus = "Queued"
|
|
135
|
+
value = "DENIED : COPIES"
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
else -> {
|
|
139
|
+
assetStatus = "Queued"
|
|
140
|
+
value = "pending"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import com.facebook.react.bridge.Arguments
|
|
2
|
+
import com.facebook.react.bridge.ReactContext
|
|
3
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
4
|
+
import com.facebook.react.bridge.WritableMap
|
|
5
|
+
import com.google.gson.Gson
|
|
6
|
+
import com.takeoffmediareactnativepenthera.PentheraModule
|
|
7
|
+
|
|
8
|
+
object PentheraEvent {
|
|
9
|
+
const val DID_START_DOWNLOADING = "DID_START_DOWNLOADING"
|
|
10
|
+
const val PROGRESS_UPDATED = "PROGRESS_UPDATED"
|
|
11
|
+
const val DOWNLOAD_COMPLETE = "DOWNLOAD_COMPLETE"
|
|
12
|
+
const val CONFIG_ASSET_FAILED = "CONFIG_ASSET_FAILED"
|
|
13
|
+
const val ASSET_RESUME_DOWNLOAD_UPDATED = "ASSET_RESUME_DOWNLOAD_UPDATED"
|
|
14
|
+
const val ASSET_DELETED = "ASSET_DELETED"
|
|
15
|
+
const val FAIR_PLAY_FAILED_INIT_DELEGATE = "FAIR_PLAY_FAILED_INIT_DELEGATE"
|
|
16
|
+
const val FAIR_PLAY_EXTRACT_CID = "FAIR_PLAY_EXTRACT_CID"
|
|
17
|
+
const val FAIR_PLAY_PREPARE_SPC = "FAIR_PLAY_PREPARE_SPC"
|
|
18
|
+
const val FAIR_PLAY_EXTRACT_CKC = "FAIR_PLAY_EXTRACT_CKC"
|
|
19
|
+
const val FAIR_PLAY_LICENSE_DELEGATE_ERROR = "FAIR_PLAY_LICENSE_DELEGATE_ERROR"
|
|
20
|
+
const val PENDING_ASSET_FOUND = "PENDING_ASSET_FOUND"
|
|
21
|
+
const val ERROR_DOWNLOAD = "ERROR_DOWNLOAD"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class EventEmitter private constructor() {
|
|
25
|
+
companion object {
|
|
26
|
+
val sharedInstance: EventEmitter by lazy { EventEmitter() }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private var eventEmitter: PentheraModule? = null
|
|
30
|
+
|
|
31
|
+
fun registerEventEmitter(eventEmitter: PentheraModule) {
|
|
32
|
+
this.eventEmitter = eventEmitter
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fun dispatch(name: String, code: String, assetId: String, body: String) {
|
|
36
|
+
val event = Event(code, assetId, body)
|
|
37
|
+
val gson = Gson()
|
|
38
|
+
val json = gson.toJson(event)
|
|
39
|
+
val reactContext = eventEmitter?.reactContext
|
|
40
|
+
reactContext!!.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
41
|
+
?.emit(name, json)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
val allEvents: List<String> by lazy {
|
|
45
|
+
val allEventNames: MutableList<String> = mutableListOf("penthera")
|
|
46
|
+
|
|
47
|
+
// Append all events here
|
|
48
|
+
|
|
49
|
+
allEventNames
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private class Event(val code: String, val assetId: String, val body: String)
|
|
53
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package com.takeoffmediareactnativepenthera
|
|
2
|
+
|
|
3
|
+
import EventEmitter
|
|
4
|
+
import android.app.Activity
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import com.facebook.react.bridge.Arguments
|
|
7
|
+
import com.facebook.react.bridge.LifecycleEventListener
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
10
|
+
import com.facebook.react.bridge.ReactMethod
|
|
11
|
+
import com.facebook.react.bridge.Promise
|
|
12
|
+
import com.facebook.react.bridge.ReadableMap
|
|
13
|
+
import com.facebook.react.bridge.WritableMap
|
|
14
|
+
import com.takeoffmediareactnativepenthera.virtuoso.OfflineVideoEngine
|
|
15
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PentheraModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
19
|
+
|
|
20
|
+
private var offlineVideoEngine: OfflineVideoEngine? = OfflineVideoEngine(reactContext)
|
|
21
|
+
private var activity: Activity? = null
|
|
22
|
+
private var appState: String = "active"
|
|
23
|
+
val reactContext: ReactApplicationContext = reactContext
|
|
24
|
+
|
|
25
|
+
override fun getName(): String = NAME
|
|
26
|
+
override fun initialize() {
|
|
27
|
+
super.initialize()
|
|
28
|
+
|
|
29
|
+
EventEmitter.sharedInstance.registerEventEmitter(this)
|
|
30
|
+
activity = currentActivity
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Example method
|
|
34
|
+
// See https://reactnative.dev/docs/native-modules-android
|
|
35
|
+
@ReactMethod
|
|
36
|
+
fun multiply(a: Double, b: Double, promise: Promise) {
|
|
37
|
+
promise.resolve(a * b)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ReactMethod
|
|
41
|
+
fun initializeSdk(user: String, backplaneUrl: String, publicKey: String, privateKey: String, promise: Promise) {
|
|
42
|
+
promise.resolve(offlineVideoEngine?.setup(user, backplaneUrl, publicKey, privateKey, activity!!))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@ReactMethod
|
|
46
|
+
fun download(data: String){
|
|
47
|
+
offlineVideoEngine?.downloadAsset(data, activity!!)
|
|
48
|
+
}
|
|
49
|
+
@ReactMethod
|
|
50
|
+
fun getDownloads(blank: String, promise: Promise) {
|
|
51
|
+
promise.resolve(offlineVideoEngine?.getDownloads())
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@ReactMethod
|
|
55
|
+
fun getByAssetId(assetId: String, promise: Promise) {
|
|
56
|
+
promise.resolve(offlineVideoEngine?.getByAssetId(assetId))
|
|
57
|
+
}
|
|
58
|
+
@ReactMethod
|
|
59
|
+
fun delete(assetId: String) {
|
|
60
|
+
offlineVideoEngine?.deleteAsset(assetId)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@ReactMethod
|
|
64
|
+
fun loadBitmovinSourceManager(assetId: String, nativeId: String, promise: Promise) {
|
|
65
|
+
val bitmovinSourceItem = offlineVideoEngine?.loadBitmovinSourceManager(assetId, nativeId)
|
|
66
|
+
promise.resolve(bitmovinSourceItem)
|
|
67
|
+
}
|
|
68
|
+
@ReactMethod
|
|
69
|
+
fun startAppStateListener() {
|
|
70
|
+
val appStateListener = { nextAppState: String ->
|
|
71
|
+
if (appState != nextAppState && nextAppState == "active") {
|
|
72
|
+
Log.e("MiModulo", "active")
|
|
73
|
+
}
|
|
74
|
+
if (appState != nextAppState && nextAppState == "background") {
|
|
75
|
+
Log.e("MiModulo", "background")
|
|
76
|
+
}
|
|
77
|
+
appState = nextAppState
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
reactContext.addLifecycleEventListener(object : LifecycleEventListener {
|
|
81
|
+
override fun onHostResume() {
|
|
82
|
+
offlineVideoEngine!!.onResume()
|
|
83
|
+
appStateListener("active")
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
override fun onHostPause() {
|
|
90
|
+
offlineVideoEngine!!.onPause()
|
|
91
|
+
appStateListener("background")
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
override fun onHostDestroy() {
|
|
95
|
+
appStateListener("inactive")
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
companion object {
|
|
102
|
+
const val NAME = "Penthera"
|
|
103
|
+
}
|
|
104
|
+
}
|