diff --git a/.DS_Store b/.DS_Store
index 5e01c35..09aad5f 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/DemoSigmaInteractiveAndroid/.idea/gradle.xml b/DemoSigmaInteractiveAndroid/.idea/gradle.xml
index 78708b3..00d25f9 100644
--- a/DemoSigmaInteractiveAndroid/.idea/gradle.xml
+++ b/DemoSigmaInteractiveAndroid/.idea/gradle.xml
@@ -4,7 +4,7 @@
-
diff --git a/DemoSigmaInteractiveAndroid/.idea/misc.xml b/DemoSigmaInteractiveAndroid/.idea/misc.xml
index 59135fb..23c7f0b 100644
--- a/DemoSigmaInteractiveAndroid/.idea/misc.xml
+++ b/DemoSigmaInteractiveAndroid/.idea/misc.xml
@@ -1,6 +1,14 @@
-
+
+
+
+
+
+
diff --git a/DemoSigmaInteractiveAndroid/.idea/runConfigurations.xml b/DemoSigmaInteractiveAndroid/.idea/runConfigurations.xml
deleted file mode 100644
index 93e4b17..0000000
--- a/DemoSigmaInteractiveAndroid/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/README.md b/DemoSigmaInteractiveAndroid/README.md
index 7fea822..178ecae 100644
--- a/DemoSigmaInteractiveAndroid/README.md
+++ b/DemoSigmaInteractiveAndroid/README.md
@@ -4,9 +4,11 @@
### I. Cài đặt
+#### 1. Tích hợp SigmaInteractive sdk
+
Thêm file [SigmaInteractiveSDK.aar](https://github.com/phamngochai123/sigma-interactive-sdk-example/blob/mobile-android/libs/SigmaInteractiveSDK.aar) vào thư mục libs cùng cấp với thư mục app của project.
-Thêm vào app/build.gradle:
+Thêm dòng sau vào app/build.gradle:
```java
dependencies {
@@ -16,108 +18,125 @@ dependencies {
}
```
-### II. Sử dụng
-
-1. Thêm SigmaInteractive sdk vào project (mục **I**).
+#### 2. Thêm khai báo appId và version sdk interactive
-2. Thêm sự kiện lắng nghe khi id3 bắt đầu parse để gửi dữ liệu cho sdk tương tác
-
- [SigmaRendererFactory](https://github.com/phamngochai123/sigma-interactive-sdk-example/blob/mobile-android/app/src/main/java/com/example/sigmainteractive/SigmaRendererFactory.java) xem trong demo
+1. Mở file `/app/res/values/strings.xml` của bạn.
+2. Thêm các thành phần `string` có tên là `interactive_app_id` và `interactive_app_version`, sau đó đặt những giá trị này thành ID và version của sdk interactive ( sẽ được gửi riêng khi đối tác tích hợp ). Ví dụ: nếu sdk có ID ứng dụng là `default-app` và version là `3.0.0` thì mã sẽ có dạng như sau:
```java
- DefaultRenderersFactory renderersFactory = new SigmaRendererFactory(getApplicationContext(), new SigmaRendererFactory.Id3ParsedListener() {
- @Override
- public void onId3Parsed(Metadata metadata) {
- if (metadata != null) {
- for (int i = 0; i < metadata.length(); i++) {
- Metadata.Entry entry = metadata.get(i);
- if (entry instanceof TextInformationFrame) {
- String des = ((TextInformationFrame) entry).description;
- String value = ((TextInformationFrame) entry).value;
- if (des.toUpperCase().equals("TXXX")) {
- if(SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView() != null) {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendID3InstantInteractive(value);
- }
- }
- }
- }
- }
- }
- });
- player = new ExoPlayer.Builder(this, renderersFactory).build();
+ default-app
+ 3.0.0
```
-
-3. Thêm sự kiện lắng nghe khi id3 trả ra đúng thời điểm hẹn giờ để gửi dữ liệu cho sdk tương tác
+3. Mở file `/app/manifest/AndroidManifest.xml`.
+4. Thêm các thành phần `meta-data` vào thành phần `application` cho ID và version của bạn:
```java
- player.addAnalyticsListener(new AnalyticsListener() {
- @Override
- public void onMetadata(AnalyticsListener.EventTime eventTime, Metadata metadata) {
- if (metadata != null) {
- for (int i = 0; i < metadata.length(); i++) {
- Metadata.Entry entry = metadata.get(i);
- if (entry instanceof TextInformationFrame) {
- String des = ((TextInformationFrame) entry).description;
- String value = ((TextInformationFrame) entry).value;
- if (des.toUpperCase().equals("TXXX")) {
- if(SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView() != null) {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendID3Interactive(value);
- }
- }
- }
- }
- }
- }
- });
+
+ ...
+
+
+ ...
+
```
-4. Tạo SigmaWebViewCallback để lắng nghe các sự kiện từ sdk tương tác.
+### II. Sử dụng
- 4.1 Trong hàm onReady gửi dữ liệu dạng json string cho sdk tương tác (bắt buộc)
+#### 1. Thêm SigmaInteractive sdk vào project (mục **I**).
- ```java
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(userData != null ? userDataSend.toString() : "{}");
- ```
+#### 2. Thêm sự kiện lắng nghe khi id3 bắt đầu parse để gửi dữ liệu cho sdk tương tác (Bắt buộc nếu hiển thị overlay)
-5. Mở view tương tác với vị trí (vị trí (x: 0, y: 0) ở góc trên bên trái màn hình), kích thước. Kích thước player, vị trí player so với view tương tác để sdk tương tác tính toán hiển thị.
+[SigmaRendererFactory](https://github.com/phamngochai123/sigma-interactive-sdk-example/blob/mobile-android/app/src/main/java/com/example/sigmainteractive/SigmaRendererFactory.java) xem trong demo
- ```java
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).openInteractiveView(xInteractiveView, yInteractiveView, widthInteractiveView, heightInteractiveView, url, sigmaWebviewCallback, widthPlayer, heightPlayer, xPlayer, yPlayer);
- ```
+```java
+DefaultRenderersFactory renderersFactory = new SigmaRendererFactory(getApplicationContext(), new SigmaRendererFactory.Id3ParsedListener() {
+ @Override
+ public void onId3Parsed(Metadata metadata) {
+ if (metadata != null) {
+ for (int i = 0; i < metadata.length(); i++) {
+ Metadata.Entry entry = metadata.get(i);
+ if (entry instanceof TextInformationFrame) {
+ String des = ((TextInformationFrame) entry).description;
+ String value = ((TextInformationFrame) entry).value;
+ if (des.toUpperCase().equals("TXXX")) {
+ if(SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView() != null) {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendID3InstantInteractive(value);
+ }
+ }
+ }
+ }
+ }
+ }
+});
+player = new ExoPlayer.Builder(this, renderersFactory).build();
+```
+
+#### 3. Thêm sự kiện lắng nghe khi id3 trả ra đúng thời điểm hẹn giờ để gửi dữ liệu cho sdk tương tác (Bắt buộc nếu hiển thị overlay)
+
+```java
+player.addAnalyticsListener(new AnalyticsListener() {
+ @Override
+ public void onMetadata(AnalyticsListener.EventTime eventTime, Metadata metadata) {
+ if (metadata != null) {
+ for (int i = 0; i < metadata.length(); i++) {
+ Metadata.Entry entry = metadata.get(i);
+ if (entry instanceof TextInformationFrame) {
+ String des = ((TextInformationFrame) entry).description;
+ String value = ((TextInformationFrame) entry).value;
+ if (des.toUpperCase().equals("TXXX")) {
+ if(SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView() != null) {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendID3Interactive(value);
+ }
+ }
+ }
+ }
+ }
+ }
+});
+```
+
+#### 4. Tạo SigmaWebViewCallback để lắng nghe các sự kiện từ sdk tương tác.
+
+4.1 Trong hàm onReady gửi dữ liệu dạng json string cho sdk tương tác (bắt buộc)
+
+ data bao gồm
+
+- token: token app ( string )
+- channelId: id của kênh đang xem ( string )
+- overlay: bật/tắt overlay (boolean, bật-true, tắt false). Nếu bật thì bắt buộc phải thêm sự kiện như mục 2-3
+- panel: bật/tắt panel (boolean, bật-true, tắt-false)
+
+```java
+SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(dataSend);
+```
+
+#### 5. Mở view tương tác với vị trí (vị trí (x: 0, y: 0) ở góc trên bên trái màn hình), kích thước. Kích thước player, vị trí player so với view tương tác để sdk tương tác tính toán hiển thị.
+
+```java
+SigmaInteractiveHelper.getInstance(PlayerActivity.this).openInteractiveView(xInteractiveView, yInteractiveView, widthInteractiveView, heightInteractiveView, url, sigmaWebviewCallback, widthPlayer, heightPlayer, xPlayer, yPlayer);
+```
- #### SigmaInteractiveHelper
#### - openInteractiveView - Mở view tương tác:
-
+
```java
SigmaInteractiveHelper.getInstance(PlayerActivity.this).openInteractiveView(xInteractive, yInteractive, widthInteractiveView, heightInteractiveView, url, sigmaWebviewCallback, widthPlayer, heightPlayer, xPlayer, yPlayer);
```
-
-
-
+
- `PlayerActivity`: Activity muốn đặt view tương tác.
-
- `xInteractive`: Vị trí muốn đặt view tương tác theo trục x.
-
- `yInteractive`: Vị trí muốn đặt view tương tác theo trục y.
-
- `widthInteractiveView`: Chiều rộng của view tương tác.
-
- `heightInteractiveView`: Chiều cao của view tương tác.
-
- `url`: Link tương tác.
-
- `widthPlayer`: Chiều rộng của player.
-
- `heightPlayer`: Chiều caocủa player.
-
- `xPlayer`: Vị trí player theo trục x.
-
- `yPlayer`: Vị trí player theo trục y.
-
- `sigmaWebviewCallback`: Nghe các sự kiện bên tương tác gọi.
-
- #### Note: Khi nhận được sự kiện onReady của sdk tương tác cần gửi dữ liệu user cho sdk qua hàm `sendOnReadyBack`
+ - *Note: Khi nhận được sự kiện onReady của sdk tương tác cần gửi dữ liệu cho sdk qua hàm `sendOnReadyBack`.
+
+ *Note: Khi nhận được sự kiện fullReload của sdk tương tác cần lấy lại token của app và gửi lại dữ liệu cho sdk qua hàm `sendOnReadyBack`
```java
ex:
@@ -133,21 +152,17 @@ private void openInteractiveView(int xInteractiveView, int yInteractiveView, int
//Sự kiện khi sdk tương tác sẵn sàng
@Override
public void onReady() {
- JSONObject userDataSend = new JSONObject();
- if (userData != null) {
- Set keys = userData.keySet();
- for (String key : keys) {
- try {
- userDataSend.put(key, JSONObject.wrap(userData.get(key)));
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- }
- SigmaWebView interactiveView = SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView();
+ SigmaWebView interactiveView = SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView();
if (interactiveView != null) {
- //gửi dữ liệu cho sdk tương tác
- interactiveView.sendOnReadyBack(userData != null ? userDataSend.toString() : "{}");
+ JSONObject dataSend = getDataSend(false);
+ Runnable sendData = new Runnable() {
+ @Override
+ public void run() {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(dataSend);
+ }
+ };
+ Handler mHandler = new Handler();
+ mHandler.post(sendData);
}
}
@@ -180,9 +195,50 @@ private void openInteractiveView(int xInteractiveView, int yInteractiveView, int
Log.d("PlayerActivity=>", "onExitFullScreen");
PlayerActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
+
+ //Sự kiện khi hệ thống tương tác yêu cầu gửi lại data
+ @Override
+ public void fullReload() {
+ //get datasend with new token
+ JSONObject newDataSend = getDataSend(true);
+ Runnable sendData = new Runnable() {
+ @Override
+ public void run() {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(newDataSend);
+ }
+ };
+ Handler mHandler = new Handler();
+ mHandler.post(sendData);
+ }
+
+ @Override
+ public void setSession(String session) {
+ Log.d("setSession=>", session);
+ }
};
SigmaInteractiveHelper.getInstance(PlayerActivity.this).openInteractiveView(xInteractiveView, yInteractiveView, widthInteractiveView, heightInteractiveView, url, sigmaWebviewCallback, widthPlayer, heightPlayer, xPlayer, yPlayer);
}
+
+
+ public JSONObject getDataSend(boolean isRefreshToken) {
+ JSONObject dataSend = null;
+ try {
+ dataSend = new JSONObject("{}");
+ //add token to dataSend if userRole is not guest
+ if(!getKeyParams(Constant.keyUserRole).equals(Constant.roleGuest)) {
+ String tokenSend = isRefreshToken ? getNewToken() : TokenManager.getTokenCache(getApplicationContext());
+ dataSend.put("token", tokenSend);
+ }
+ //send id channel
+ dataSend.put("channelId", getKeyParams(Constant.keyChannelId));
+ //on-off overlay, panel (on-true, off-false)
+ dataSend.put("overlay", true);
+ dataSend.put("panel", true);
+ } catch (JSONException err){
+ Log.d("Error", err.toString());
+ }
+ return dataSend;
+ }
```
#### - getInteractiveView - lấy view tương tác hiện tại
@@ -251,33 +307,43 @@ SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView
```
- `xInteractive`: Vị trí muốn đặt view tương tác theo trục x.
-
- `yInteractive`: Vị trí muốn đặt view tương tác theo trục y.
-
- `widthInteractiveView`: Chiều rộng của view tương tác.
-
- `heightInteractiveView`: Chiều cao của view tương tác.
-
- `widthPlayer`: Chiều rộng của player.
-
- `heightPlayer`: Chiều caocủa player.
-
- `xPlayer`: Vị trí player theo trục x.
-
- `yPlayer`: Vị trí player theo trục y.
```java
- ex:
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- Log.d("onConfigurationChanged", String.valueOf(newConfig.orientation));
- super.onConfigurationChanged(newConfig);
- if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, containerView.getLayoutParams().width, containerView.getLayoutParams().height, containerView.getLayoutParams().width, containerView.getLayoutParams().height, 0, 0);
- } else {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, containerView.getLayoutParams().width, containerView.getLayoutParams().height, containerView.getLayoutParams().width, containerView.getLayoutParams().height, 0, 0);
- }
- }
+ ex:@Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ setLayoutInteractive(newConfig);
+ }
+ public void setLayoutInteractive(Configuration newConfig) {
+ final View view = findViewById(android.R.id.content);
+ ViewTreeObserver observer = view.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ //event when screen rotation is done
+ @Override
+ public void onGlobalLayout() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = containerView.getHeight();
+ int width = containerView.getWidth();
+ StyledPlayerView playerView = (StyledPlayerView) findViewById(R.id.player_view);
+ int widthPlayer = playerView.getWidth();
+ int heightPlayer = playerView.getHeight();
+ if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, width, height, widthPlayer, heightPlayer, 0, 0);
+ } else {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, width, height, widthPlayer, heightPlayer, 0, 0);
+ }
+ view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
+ }
```
#### - clearInterActiveView - xóa view tương tác
@@ -296,4 +362,4 @@ protected void onDestroy() {
super.onDestroy();
...
}
-```
\ No newline at end of file
+```
diff --git a/DemoSigmaInteractiveAndroid/app/build.gradle b/DemoSigmaInteractiveAndroid/app/build.gradle
index 5b04bb5..8e666b1 100644
--- a/DemoSigmaInteractiveAndroid/app/build.gradle
+++ b/DemoSigmaInteractiveAndroid/app/build.gradle
@@ -44,5 +44,6 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.exoplayer:exoplayer:2.17.0'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.17.0'
+ implementation 'com.auth0:java-jwt:3.19.2'
implementation files('../libs/SigmaInteractiveSDK.aar')
}
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/AndroidManifest.xml b/DemoSigmaInteractiveAndroid/app/src/main/AndroidManifest.xml
index 6cbb9c1..468f5a2 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/AndroidManifest.xml
+++ b/DemoSigmaInteractiveAndroid/app/src/main/AndroidManifest.xml
@@ -25,6 +25,12 @@
+
+
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/Constant.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/Constant.java
new file mode 100644
index 0000000..6a709bd
--- /dev/null
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/Constant.java
@@ -0,0 +1,25 @@
+package com.example.sigmainteractive;
+
+public class Constant {
+ static final String string = "string";
+ static final String bool = "bool";
+ static final String number = "number";
+ static final String keyField = "key";
+ static final String valueField = "value";
+ static final String typeField = "type";
+ static final String idField = "id";
+ static final String expField = "exp";
+ static final String roleField = "role";
+ static final String roleUser = "user";
+ static final String roleAdmin = "admin";
+ static final String roleGuest = "guest";
+ static final String appIdField = "appId";
+ static final String userDataField = "userData";
+ static final String keyUserRole = "userRole";
+ static final String keyUserId = "userId";
+ static final String keyChannelId = "channelId";
+ static final String keyVideoLink = "videoLink";
+ static final String keyUserData = "userData";
+ static final String keySharePreferences = "app_shared_preferences";
+ static final String keyAccessToken = "accessToken";
+}
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/ListChannel.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/ListChannel.java
new file mode 100644
index 0000000..034a3ac
--- /dev/null
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/ListChannel.java
@@ -0,0 +1,35 @@
+package com.example.sigmainteractive;
+
+public class ListChannel {
+ static final String baseUrlChannel = "https://dev-livestream.gviet.vn/manifest/";
+ static final String vtv1Key = "vtv1";
+ static final String vtv2Key = "vtv2";
+ static final String vtv3Key = "vtv3";
+ static final String vtv4Key = "vtv4";
+ static public String getSource(String channelId) {
+ switch (channelId) {
+ case vtv1Key:
+ return baseUrlChannel + "VTV1-PACKAGE/master.m3u8";
+ case vtv2Key:
+ return baseUrlChannel + "VTV2-PACKAGE/master.m3u8";
+ case vtv3Key:
+ return baseUrlChannel + "VTV3-PACKAGE/master.m3u8";
+ case vtv4Key:
+ return baseUrlChannel + "VTV4/master.m3u8";
+ default: return "";
+ }
+ }
+ static public String getId(String channelKey) {
+ switch (channelKey) {
+ case vtv1Key:
+ return "c9c2ebfb-2887-4de6-aec4-0a30aa848915";
+ case vtv2Key:
+ return "32a55ed3-4ee1-42f8-819a-407b54a39923";
+ case vtv3Key:
+ return "60346597-8ed9-48de-bd4d-8546d0070c7c";
+ case vtv4Key:
+ return "22e1fdb6-8d10-4193-8411-562c7104aa2b";
+ default: return "c9c2ebfb-2887-4de6-aec4-0a30aa848915";
+ }
+ }
+}
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/MainActivity.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/MainActivity.java
index dd220ef..4b84e9b 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/MainActivity.java
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/MainActivity.java
@@ -2,34 +2,365 @@
import androidx.appcompat.app.AppCompatActivity;
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.TextWatcher;
import android.util.Log;
+import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.TextView;
import com.google.android.material.textfield.TextInputEditText;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
public class MainActivity extends AppCompatActivity {
Button btnOpenPlayer;
+ Button btnGetChannel;
+ public String channelId = ListChannel.getId("vtv1");
+ public String typeFiled = Constant.string;
+ public JSONArray dataUser = new JSONArray();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOpenPlayer = findViewById(R.id.openPlayer);
+ btnGetChannel = findViewById(R.id.btnGetChannel);
+ TextInputEditText txtVideo = findViewById(R.id.txtLinkVideo);
+ txtVideo.setText(ListChannel.getSource(ListChannel.vtv1Key));
+ checkAndShowBtnOpenWithOldConfig();
+ }
+ public void checkAndShowBtnOpenWithOldConfig() {
+ TextInputEditText txtUid = findViewById(R.id.txtUid);
+ String accessTokenCache = SharePreferencesBase.getInstance(getApplicationContext()).getValue(Constant.keyAccessToken);
+ String userIdCache = SharePreferencesBase.getInstance(getApplicationContext()).getValue(Constant.keyUserId);
+ String userRoleCache = SharePreferencesBase.getInstance(getApplicationContext()).getValue(Constant.keyUserRole);
+ if(accessTokenCache != null && userIdCache != null && userRoleCache != null && accessTokenCache.length() > 0 && userIdCache.length() > 0 && userRoleCache.length() > 0) {
+ Button btnOpenOldConfig = findViewById(R.id.btnOpenWithOldConfig);
+ btnOpenOldConfig.setVisibility(View.VISIBLE);
+ txtUid.setText(userIdCache);
+ RadioGroup groupRoleUser = findViewById(R.id.groupRoleUser);
+ switch (userRoleCache) {
+ case Constant.roleAdmin:
+ groupRoleUser.check(R.id.roleAdmin);
+ break;
+ case Constant.roleGuest:
+ groupRoleUser.check(R.id.roleGuest);
+ break;
+ case Constant.roleUser:
+ groupRoleUser.check(R.id.roleUser);
+ break;
+ default:break;
+ }
+ }
}
-
public void openPlayerActivity(View view) {
TextInputEditText txtInput = findViewById(R.id.txtInputLink);
TextInputEditText txtVideo = findViewById(R.id.txtLinkVideo);
+ TextInputEditText txtUid = findViewById(R.id.txtUid);
Log.d("input link", txtInput.getText().toString());
String inputLinkInteractive = txtInput.getText().toString();
String inputVideoUrl = txtVideo.getText().toString();
Intent myIntent = new Intent(MainActivity.this, PlayerActivity.class);
- if(inputLinkInteractive.length() > 0) {
+ if (inputLinkInteractive.length() > 0) {
+ myIntent.putExtra("interactiveLink", inputLinkInteractive); //Optional parameters
+ myIntent.putExtra("videoLink", inputVideoUrl); //Optional parameters
+ }
+ RadioGroup groupRoleUser = findViewById(R.id.groupRoleUser);
+ int idRole = groupRoleUser.getCheckedRadioButtonId();
+ String userRole = Constant.roleUser;
+ switch (idRole) {
+ case R.id.roleAdmin:
+ userRole = Constant.roleAdmin;
+ break;
+ case R.id.roleGuest:
+ userRole = Constant.roleGuest;
+ break;
+ default:break;
+ }
+ long exp = System.currentTimeMillis() + 30*24*60*60*1000;
+ String token = TokenManager.genToken(String.valueOf(txtUid.getText()), userRole, exp, dataUser, getApplicationContext());
+ myIntent.putExtra(Constant.keyUserRole, userRole);
+ myIntent.putExtra(Constant.keyUserId, String.valueOf(txtUid.getText()));
+ myIntent.putExtra(Constant.keyChannelId, channelId);
+ myIntent.putExtra(Constant.keyUserData, dataUser.toString());
+ MainActivity.this.startActivity(myIntent);
+ checkAndShowBtnOpenWithOldConfig();
+ }
+ public void openPlayerWithOldConfig(View view) {
+ TextInputEditText txtInput = findViewById(R.id.txtInputLink);
+ TextInputEditText txtVideo = findViewById(R.id.txtLinkVideo);
+ String inputLinkInteractive = txtInput.getText().toString();
+ String inputVideoUrl = txtVideo.getText().toString();
+ Intent myIntent = new Intent(MainActivity.this, PlayerActivity.class);
+ if (inputLinkInteractive.length() > 0) {
myIntent.putExtra("interactiveLink", inputLinkInteractive); //Optional parameters
myIntent.putExtra("videoLink", inputVideoUrl); //Optional parameters
+ myIntent.putExtra(Constant.keyChannelId, channelId);
+ myIntent.putExtra(Constant.keyUserData, SharePreferencesBase.getInstance(getApplicationContext()).getUserData());
+ myIntent.putExtra(Constant.keyUserRole, SharePreferencesBase.getInstance(getApplicationContext()).getUserRole());
+ myIntent.putExtra(Constant.keyUserId, SharePreferencesBase.getInstance(getApplicationContext()).getUserId());
}
MainActivity.this.startActivity(myIntent);
}
+ @SuppressLint("ResourceAsColor")
+ public void addFieldDataUser() {
+ try {
+ int idView = View.generateViewId();
+ LinearLayout containerUserData = findViewById(R.id.containerUserData);
+ LinearLayout containerUserField = new LinearLayout(this);
+ containerUserField.setId(idView);
+ containerUserField.setOrientation(LinearLayout.VERTICAL);
+ containerUserField.setGravity(Gravity.CENTER_HORIZONTAL);
+ //wrap input
+ LinearLayout wrapUserField = new LinearLayout(this);
+ wrapUserField.setOrientation(LinearLayout.HORIZONTAL);
+ //left
+ LinearLayout wrapUserFieldLeft = new LinearLayout(this);
+ wrapUserFieldLeft.setOrientation(LinearLayout.VERTICAL);
+ LinearLayout.LayoutParams paramField = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ 1.0f
+ );
+ wrapUserFieldLeft.setLayoutParams(paramField);
+ TextView titleLeft = new TextView(this);
+ titleLeft.setText("Key");
+ TextInputEditText txtInputKey = new TextInputEditText(this);
+ txtInputKey.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
+ wrapUserFieldLeft.addView(titleLeft);
+ wrapUserFieldLeft.addView(txtInputKey);
+ //right
+ LinearLayout wrapUserFieldRight = new LinearLayout(this);
+ wrapUserFieldRight.setOrientation(LinearLayout.VERTICAL);
+ wrapUserFieldRight.setLayoutParams(paramField);
+ TextView titleRight = new TextView(this);
+ titleRight.setText("Value");
+ wrapUserFieldRight.addView(titleRight);
+ txtInputKey.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ Log.d("onTextChanged=>", String.valueOf(s));
+ changeFieldUser(idView, Constant.keyField, String.valueOf(s), 0, false, true);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ }
+ });
+ switch (typeFiled) {
+ case Constant.bool:
+ RadioGroup listValue = new RadioGroup(this);
+ listValue.setOrientation(LinearLayout.HORIZONTAL);
+ listValue.setLayoutParams(paramField);
+ listValue.setGravity(Gravity.CENTER_HORIZONTAL);
+ RadioButton itemTrue = new RadioButton(this);
+ RadioGroup.LayoutParams paramsItemTrue = new RadioGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ paramsItemTrue.setMargins(0, 0, 15, 0);
+ itemTrue.setLayoutParams(paramsItemTrue);
+ itemTrue.setText("True");
+ int idItemTrue = View.generateViewId();
+ itemTrue.setId(idItemTrue);
+ itemTrue.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Log.d("onCheckedChanged=>true", String.valueOf(isChecked));
+// changeFieldUser(idView, Constant.valueField, "", 0, true, false);
+ }
+ });
+ //item false
+ RadioButton itemFalse = new RadioButton(this);
+ int idItemFalse = View.generateViewId();
+ itemFalse.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ Log.d("onCheckedChanged=>false", String.valueOf(isChecked));
+// changeFieldUser(idView, Constant.valueField, "", 0, false, false);
+ }
+ });
+ itemFalse.setText("False");
+ itemFalse.setId(idItemFalse);
+ listValue.addView(itemTrue);
+ listValue.addView(itemFalse);
+ listValue.check(idItemTrue);
+ wrapUserFieldRight.addView(listValue);
+ listValue.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(RadioGroup group, int checkedId) {
+ Log.d("onCheckedChanged=>root", String.valueOf(checkedId));
+ changeFieldUser(idView, Constant.valueField, "", 0, checkedId != idItemFalse, false);
+ }
+ });
+ break;
+ case Constant.string:
+ case Constant.number:
+ TextInputEditText txtInputValue = new TextInputEditText(this);
+ txtInputValue.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
+ if(typeFiled.equals(Constant.number)) {
+ txtInputValue.setInputType(InputType.TYPE_CLASS_NUMBER);
+ }
+ txtInputValue.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ Log.d("onTextChanged=>", String.valueOf(s));
+ changeFieldUser(idView, Constant.valueField, typeFiled.equals(Constant.string) ? String.valueOf(s) : "", typeFiled.equals(Constant.number) ? Integer.parseInt(String.valueOf(s)) : 0, false, false);
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+
+ }
+ });
+ wrapUserFieldRight.addView(txtInputValue);
+ break;
+ default:
+ break;
+ }
+ //button delete
+ LinearLayout.LayoutParams paramsButton = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ );
+ paramsButton.setMargins(0, 10, 0, 20);
+ Button buttonDelete = new Button(this);
+ buttonDelete.setText("Delete");
+ buttonDelete.setWidth(50);
+ buttonDelete.setLayoutParams(paramsButton);
+ buttonDelete.setBackgroundColor(getResources().getColor(R.color.red));
+ GradientDrawable shape = new GradientDrawable();
+ shape.setCornerRadius(8);
+ shape.setColor(Color.RED);
+ buttonDelete.setBackground(shape);
+ buttonDelete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ try {
+ int indexDelete = 0;
+ for(int i=0; iAlertDialog.Builder with its constructor
+ AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+
+// 2. Chain together various setter methods to set the dialog characteristics
+ final CharSequence[] items = {Constant.string, Constant.bool, Constant.number};
+ builder.setTitle("Select type").setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("onClick=>", String.valueOf(items[which]));
+ typeFiled = String.valueOf(items[which]);
+ addFieldDataUser();
+ }
+ });
+// 3. Get the AlertDialog from create()
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ public void openListChannel(View view) {
+ // 1. Instantiate an AlertDialog.Builder with its constructor
+ AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
+
+// 2. Chain together various setter methods to set the dialog characteristics
+ final CharSequence[] items = {ListChannel.vtv1Key, ListChannel.vtv2Key, ListChannel.vtv3Key, ListChannel.vtv4Key};
+ builder.setTitle("Select channel").setItems(items, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Log.d("onClick=>", String.valueOf(items[which]));
+ String source = ListChannel.getSource((String) items[which]);
+ channelId = ListChannel.getId((String) items[which]);
+ Log.d("source=>", source);
+ TextInputEditText txtVideo = findViewById(R.id.txtLinkVideo);
+ txtVideo.setText(source);
+ }
+ });
+// 3. Get the AlertDialog from create()
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
}
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/PlayerActivity.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/PlayerActivity.java
index 549e452..6d75cc0 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/PlayerActivity.java
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/PlayerActivity.java
@@ -10,13 +10,17 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -27,20 +31,23 @@
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
+import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.ui.StyledPlayerView;
+import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Calendar;
+import java.util.HashMap;
import java.util.Set;
-public class PlayerActivity extends Activity {
+public class PlayerActivity extends Activity implements Player.Listener {
View containerView;
- // private static boolean DEBUG = false;
- public static final String VERSION = "2.0.0";
+ public static final String VERSION = "3.0.0";
private static final String HTML_SDK = "https://dev-livestream.gviet.vn/ilp-statics/[SDK_VERSION]/android-mobile-interactive.html";
private static String sourcePlay = "https://dev-livestream.gviet.vn/manifest/VTV2-PACKAGE/master.m3u8";
ExoPlayer player;
@@ -50,9 +57,9 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
- //
setContentView(R.layout.activity_player);
containerView = this.findViewById(android.R.id.content);
+// setKeyboardVisibilityListener(this);
isPlaying = false;
DefaultRenderersFactory renderersFactory = new SigmaRendererFactory(getApplicationContext(), new SigmaRendererFactory.Id3ParsedListener() {
@Override
@@ -97,41 +104,107 @@ public void onMetadata(AnalyticsListener.EventTime eventTime, Metadata metadata)
});
StyledPlayerView playerView = (StyledPlayerView) findViewById(R.id.player_view);
playerView.setPlayer(player);
+ sourcePlay = getKeyParams(Constant.keyVideoLink);
+ setupPlayer();
+ }
+ public String getKeyParams(String key) {
+ Log.d("getKeyParams=>", key);
Bundle params = getIntent().getExtras();
- if (params != null && params.getString("videoLink").length() > 0) {
- sourcePlay = params.getString("videoLink");
+ if (params != null && params.getString(key).length() > 0) {
+ return params.getString(key);
+ }
+ return "";
+ }
+ @Override
+ public void onIsPlayingChanged(boolean isPlaying) {
+ Player.Listener.super.onIsPlayingChanged(isPlaying);
+ }
+
+ @Override
+ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
+ Player.Listener.super.onPlayerStateChanged(playWhenReady, playbackState);
+ Log.d("onPlayerStateChanged=>", String.valueOf(playbackState));
+ if(playbackState == Player.STATE_READY && SigmaInteractiveHelper.getInstance(PlayerActivity.this).interactiveView == null) {
+ Log.d("onPlayerStateChanged=>", "ready");
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = displayMetrics.heightPixels;
+ int width = displayMetrics.widthPixels;
+ StyledPlayerView playerView = (StyledPlayerView) findViewById(R.id.player_view);
+ int widthPlayer = playerView.getWidth();
+ int heightPlayer = playerView.getHeight();
+ this.openInteractiveView(0, 0, width, height, widthPlayer, heightPlayer, 0, 0);
}
- setupPlayer();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
- Log.d("onConfigurationChanged", String.valueOf(newConfig.orientation));
super.onConfigurationChanged(newConfig);
- if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, containerView.getLayoutParams().width, containerView.getLayoutParams().height, containerView.getLayoutParams().width, containerView.getLayoutParams().height, 0, 0);
- } else {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, containerView.getLayoutParams().width, containerView.getLayoutParams().height, containerView.getLayoutParams().width, containerView.getLayoutParams().height, 0, 0);
- }
+ setLayoutInteractive(newConfig);
+ }
+ public void setLayoutInteractive(Configuration newConfig) {
+ final View view = findViewById(android.R.id.content);
+ ViewTreeObserver observer = view.getViewTreeObserver();
+ observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+ int height = containerView.getHeight();
+ int width = containerView.getWidth();
+ StyledPlayerView playerView = (StyledPlayerView) findViewById(R.id.player_view);
+ int widthPlayer = playerView.getWidth();
+ int heightPlayer = playerView.getHeight();
+ if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, width, height, widthPlayer, heightPlayer, 0, 0);
+ } else {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).setLayoutInteractiveView(0, 0, width, height, widthPlayer, heightPlayer, 0, 0);
+ }
+ view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ }
+ });
}
private void setupPlayer(){
Uri videoUri = Uri.parse(sourcePlay);
MediaItem mediaItem = MediaItem.fromUri(videoUri);
// Set the media item to be played.
player.setMediaItem(mediaItem);
+ player.addListener(this);
// Prepare the player.
player.prepare();
// Start the playback.
player.play();
+ player.setPlayWhenReady(true);
isPlaying = true;
- DisplayMetrics displayMetrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
- int height = displayMetrics.heightPixels;
- int width = displayMetrics.widthPixels;
- this.openInteractiveView(0, 0, width, height, width, height, 0, 0, null);
}
-
- private void openInteractiveView(int xInteractiveView, int yInteractiveView, int widthInteractiveView, int heightInteractiveView, int widthPlayer, int heightPlayer, int xPlayer, int yPlayer, Bundle userData) {
+ public String getNewToken() throws JSONException {
+ try {
+ String userRole = getKeyParams(Constant.keyUserRole);
+ String userId = getKeyParams(Constant.keyUserId);
+ String dataUserString = getKeyParams(Constant.keyUserData);
+ return TokenManager.genToken(userId, userRole, System.currentTimeMillis() + 30*24*60*60*1000, new JSONArray(dataUserString), getApplicationContext());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+ public JSONObject getDataSend(boolean isRefreshToken) {
+ JSONObject dataSend = null;
+ try {
+ dataSend = new JSONObject("{}");
+ if(!getKeyParams(Constant.keyUserRole).equals(Constant.roleGuest)) {
+ String tokenSend = isRefreshToken ? getNewToken() : TokenManager.getTokenCache(getApplicationContext());
+ dataSend.put("token", tokenSend);
+ }
+ dataSend.put("channelId", getKeyParams(Constant.keyChannelId));
+ dataSend.put("overlay", true);
+ dataSend.put("panel", true);
+ } catch (JSONException err){
+ Log.d("Error", err.toString());
+ }
+ return dataSend;
+ }
+ private void openInteractiveView(int xInteractiveView, int yInteractiveView, int widthInteractiveView, int heightInteractiveView, int widthPlayer, int heightPlayer, int xPlayer, int yPlayer) {
if (containerView == null) return;
Bundle params = getIntent().getExtras();
String interactiveLink = ""; // or other values
@@ -144,21 +217,17 @@ private void openInteractiveView(int xInteractiveView, int yInteractiveView, int
//Sự kiện khi sdk tương tác sẵn sàng
@Override
public void onReady() {
- JSONObject userDataSend = new JSONObject();
- if (userData != null) {
- Set keys = userData.keySet();
- for (String key : keys) {
- try {
- userDataSend.put(key, JSONObject.wrap(userData.get(key)));
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- }
SigmaWebView interactiveView = SigmaInteractiveHelper.getInstance(PlayerActivity.this).getInteractiveView();
- Log.d("onReady=>", userDataSend.toString());
if (interactiveView != null) {
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(userData != null ? userDataSend.toString() : "{}");
+ JSONObject dataSend = getDataSend(false);
+ Runnable sendData = new Runnable() {
+ @Override
+ public void run() {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(dataSend);
+ }
+ };
+ Handler mHandler = new Handler();
+ mHandler.post(sendData);
}
}
@@ -191,23 +260,47 @@ public void onExitFullScreen() {
Log.d("PlayerActivity=>", "onExitFullScreen");
PlayerActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
+ //Sự kiện khi hệ thống tương tác yêu cầu gửi lại data
+ @Override
+ public void fullReload() {
+ //get datasend with new token
+ JSONObject newDataSend = getDataSend(true);
+ Runnable sendData = new Runnable() {
+ @Override
+ public void run() {
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).sendOnReadyBack(newDataSend);
+ }
+ };
+ Handler mHandler = new Handler();
+ mHandler.post(sendData);
+ }
+
+ @Override
+ public void setSession(String session) {
+ Log.d("setSession=>", session);
+ }
};
SigmaInteractiveHelper.getInstance(PlayerActivity.this).openInteractiveView(xInteractiveView, yInteractiveView, widthInteractiveView, heightInteractiveView, url, sigmaWebviewCallback, widthPlayer, heightPlayer, xPlayer, yPlayer);
}
@Override
protected void onDestroy() {
+ Log.d("onPlayerStateChanged=>", "onDestroy");
+ SigmaInteractiveHelper.getInstance(PlayerActivity.this).clearInterActiveView();
player.release();
isPlaying = false;
- SigmaInteractiveHelper.getInstance(PlayerActivity.this).clearInterActiveView();
super.onDestroy();
}
@Override
protected void onPause() {
- // simpleExoPlayer.setPlayWhenReady(false);
- player.release();
isPlaying = false;
super.onPause();
}
+ @Override
+ protected void onStop() {
+ isPlaying = false;
+ super.onStop();
+ }
+
}
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/SharePreferencesBase.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/SharePreferencesBase.java
new file mode 100644
index 0000000..5455378
--- /dev/null
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/SharePreferencesBase.java
@@ -0,0 +1,58 @@
+package com.example.sigmainteractive;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+public class SharePreferencesBase {
+ private static SharePreferencesBase INSTANCE = null;
+ public static SharedPreferences mSharedPreferences = null;
+ public static String userId = "";
+ public static String userRole = "";
+ public static String userData = "";
+ public static String accessToken = "";
+
+ public static SharePreferencesBase getInstance(Context context) {
+ if (INSTANCE == null) {
+ INSTANCE = new SharePreferencesBase(context);
+ }
+ return INSTANCE;
+ }
+
+ public String getUserId() {
+ return getValue(Constant.keyUserId);
+ }
+
+ public String getUserRole() {
+ return getValue(Constant.keyUserRole);
+ }
+
+ public String getUserData() {
+ return getValue(Constant.keyUserData);
+ }
+
+ public String getAccessToken() {
+ return getValue(Constant.keyAccessToken);
+ }
+
+ public SharePreferencesBase(Context context) {
+ mSharedPreferences = context.getSharedPreferences(Constant.keySharePreferences, Context.MODE_PRIVATE);
+ userId = this.getValue(Constant.keyUserId);
+ accessToken = this.getValue(Constant.keyAccessToken);
+ userRole = this.getValue(Constant.keyUserRole);
+ userData = this.getValue(Constant.keyUserData);
+ }
+
+ public String getValue(String name) {
+ return mSharedPreferences.getString(name, null);
+ }
+
+ public void setValue(String name, String value) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putString(name, value).apply();
+ }
+ public void deleteKey(String key) {
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.remove(key).apply();
+ }
+
+}
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/TokenManager.java b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/TokenManager.java
new file mode 100644
index 0000000..47091af
--- /dev/null
+++ b/DemoSigmaInteractiveAndroid/app/src/main/java/com/example/sigmainteractive/TokenManager.java
@@ -0,0 +1,81 @@
+package com.example.sigmainteractive;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTCreator;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTCreationException;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TokenManager {
+ static public final String key = "abd89b50-d760-4a97-bb24-0a44881fc04a";
+ static public String genToken(String userId, String userRole, long exp, JSONArray userData, Context context) {
+ String token = "";
+ Log.d("genToken=>", userId);
+ Log.d("genToken=>", userRole);
+ Map payloadClaims = new HashMap<>();
+ payloadClaims.put(Constant.idField, userId);
+ payloadClaims.put(Constant.expField, exp);
+ payloadClaims.put(Constant.roleField, userRole);
+ SharePreferencesBase.getInstance(context).setValue(Constant.keyUserRole, userRole);
+ SharePreferencesBase.getInstance(context).setValue(Constant.keyUserId, userId);
+ try {
+ ApplicationInfo app = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ payloadClaims.put(Constant.appIdField, app.metaData.getString("com.sigma.interactive.sdk.appId"));
+ Algorithm algorithm = Algorithm.HMAC256(key);
+ JWTCreator.Builder builder = JWT.create();
+ Map payloadUserData = new HashMap<>();
+ for(int i=0; i 0) {
+ switch (itemField.getString(Constant.typeField)) {
+ case Constant.string:
+ String valueField = itemField.getString(Constant.valueField);
+ if(valueField.length() > 0) {
+ payloadUserData.put(itemField.getString(Constant.keyField), itemField.getString(Constant.valueField));
+ }
+ break;
+ case Constant.number:
+ payloadUserData.put(itemField.getString(Constant.keyField), itemField.getInt(Constant.valueField));
+ break;
+ case Constant.bool:
+ payloadUserData.put(itemField.getString(Constant.keyField), itemField.getBoolean(Constant.valueField));
+ break;
+ default:break;
+ }
+ }
+ }
+ Log.d("payloadUserData=>", String.valueOf(payloadUserData.size()));
+ if(payloadUserData.size() > 0) {
+ payloadClaims.put(Constant.userDataField, payloadUserData);
+ SharePreferencesBase.getInstance(context).setValue(Constant.keyUserData, userData.toString());
+ } else {
+ SharePreferencesBase.getInstance(context).deleteKey(Constant.keyUserData);
+ }
+ token = builder.withPayload(payloadClaims).sign(algorithm);
+ } catch (JWTCreationException | JSONException| PackageManager.NameNotFoundException exception){
+ //Invalid Signing configuration / Couldn't convert Claims.
+ }
+ Log.d("TokenGenerate=>", token);
+ setTokenCache(token, context);
+ return token;
+ }
+ static public void setTokenCache(String token, Context context) {
+ SharePreferencesBase.getInstance(context).setValue(Constant.keyAccessToken, token);
+ }
+ static public String getTokenCache(Context context) {
+ return SharePreferencesBase.getInstance(context).getValue(Constant.keyAccessToken);
+ }
+}
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_main.xml b/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_main.xml
index 9118b5d..fc0d05a 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_main.xml
+++ b/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_main.xml
@@ -21,77 +21,225 @@
android:layout_height="match_parent"
android:keepScreenOn="true">
-
+ android:layout_height="match_parent">
-
+ android:layout_height="match_parent">
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp"
+ android:text="Data"
+ android:textAlignment="center" />
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
+ android:layout_marginBottom="50dp"
+ android:background="#03A9F4"
+ android:backgroundTint="#03A9F4"
+ android:onClick="openSelectTypeField"
+ android:text="Add Field" />
+
+
+
+
-
+
-
+
+
-
-
+
+
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_player.xml b/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_player.xml
index bdc266f..78b81d6 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_player.xml
+++ b/DemoSigmaInteractiveAndroid/app/src/main/res/layout/activity_player.xml
@@ -5,16 +5,21 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
+ android:fitsSystemWindows="true"
tools:context=".PlayerActivity">
-
+
+
+
+
+
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/res/values/colors.xml b/DemoSigmaInteractiveAndroid/app/src/main/res/values/colors.xml
index 9dbfa70..0454db0 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/res/values/colors.xml
+++ b/DemoSigmaInteractiveAndroid/app/src/main/res/values/colors.xml
@@ -10,4 +10,5 @@
#008577
#00574B
#D81B60
+ #FF0000
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/app/src/main/res/values/strings.xml b/DemoSigmaInteractiveAndroid/app/src/main/res/values/strings.xml
index e9a3a13..d60d219 100644
--- a/DemoSigmaInteractiveAndroid/app/src/main/res/values/strings.xml
+++ b/DemoSigmaInteractiveAndroid/app/src/main/res/values/strings.xml
@@ -10,4 +10,6 @@
Hello first fragment
Hello second fragment. Arg: %1$s
+ default-app
+ 3.0.0
\ No newline at end of file
diff --git a/DemoSigmaInteractiveAndroid/libs/SigmaInteractiveSDK.aar b/DemoSigmaInteractiveAndroid/libs/SigmaInteractiveSDK.aar
index 5474335..58d57d2 100644
Binary files a/DemoSigmaInteractiveAndroid/libs/SigmaInteractiveSDK.aar and b/DemoSigmaInteractiveAndroid/libs/SigmaInteractiveSDK.aar differ
diff --git a/DemoSigmaInteractiveIOS/.DS_Store b/DemoSigmaInteractiveIOS/.DS_Store
index 821fdfc..580784c 100644
Binary files a/DemoSigmaInteractiveIOS/.DS_Store and b/DemoSigmaInteractiveIOS/.DS_Store differ
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.pbxproj b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.pbxproj
index 27989f4..e17619f 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.pbxproj
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.pbxproj
@@ -7,7 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
- 9B4F04B52812ACF40002F0CB /* SigmaInteractiveSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9B4F04B42812ACF40002F0CB /* SigmaInteractiveSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 9B66464228517FC1005E0399 /* PopupWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B66464128517FC1005E0399 /* PopupWindow.swift */; };
+ 9B6646472852DB23005E0399 /* CodableExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6646462852DB23005E0399 /* CodableExtensions.swift */; };
+ 9B6646492852DB59005E0399 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B6646482852DB59005E0399 /* Utility.swift */; };
+ 9B66464B2852EBF8005E0399 /* GenerateToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B66464A2852EBF8005E0399 /* GenerateToken.swift */; };
+ 9B66464D2852F1C3005E0399 /* PopupSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B66464C2852F1C3005E0399 /* PopupSelect.swift */; };
9B7D8F6A27F43D4000C683D4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D8F6927F43D4000C683D4 /* AppDelegate.swift */; };
9B7D8F6C27F43D4000C683D4 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D8F6B27F43D4000C683D4 /* SceneDelegate.swift */; };
9B7D8F6E27F43D4000C683D4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D8F6D27F43D4000C683D4 /* ViewController.swift */; };
@@ -16,16 +20,18 @@
9B7D8F7627F43D4D00C683D4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9B7D8F7427F43D4D00C683D4 /* LaunchScreen.storyboard */; };
9B7D8F9127F567A300C683D4 /* PlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7D8F9027F567A300C683D4 /* PlayerViewController.swift */; };
9B85CBF327FAA3A700B7C935 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B85CBF227FAA3A700B7C935 /* AppUtility.swift */; };
+ 9BBF1A70288E9564003A6DF2 /* SigmaInteractiveSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BBF1A6F288E9564003A6DF2 /* SigmaInteractiveSDK.framework */; };
+ 9BBF1A72288E9572003A6DF2 /* SigmaInteractiveSDK.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9BBF1A71288E9572003A6DF2 /* SigmaInteractiveSDK.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
- 9B4F0446281276850002F0CB /* Embed Frameworks */ = {
+ 9BF0591B287420BE005DB1B6 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
- buildActionMask = 12;
+ buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
- 9B4F04B52812ACF40002F0CB /* SigmaInteractiveSDK.framework in Embed Frameworks */,
+ 9BBF1A72288E9572003A6DF2 /* SigmaInteractiveSDK.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -33,7 +39,11 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 9B4F04B42812ACF40002F0CB /* SigmaInteractiveSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SigmaInteractiveSDK.framework; path = "../sdk-interactive-mobile-ios/SigmaInteractiveSDK.framework"; sourceTree = ""; };
+ 9B66464128517FC1005E0399 /* PopupWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupWindow.swift; sourceTree = ""; };
+ 9B6646462852DB23005E0399 /* CodableExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableExtensions.swift; sourceTree = ""; };
+ 9B6646482852DB59005E0399 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = ""; };
+ 9B66464A2852EBF8005E0399 /* GenerateToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenerateToken.swift; sourceTree = ""; };
+ 9B66464C2852F1C3005E0399 /* PopupSelect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupSelect.swift; sourceTree = ""; };
9B7D8F6627F43D4000C683D4 /* DemoSigmaInteractive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoSigmaInteractive.app; sourceTree = BUILT_PRODUCTS_DIR; };
9B7D8F6927F43D4000C683D4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
9B7D8F6B27F43D4000C683D4 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
@@ -44,6 +54,8 @@
9B7D8F7727F43D4D00C683D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
9B7D8F9027F567A300C683D4 /* PlayerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerViewController.swift; sourceTree = ""; };
9B85CBF227FAA3A700B7C935 /* AppUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUtility.swift; sourceTree = ""; };
+ 9BBF1A6F288E9564003A6DF2 /* SigmaInteractiveSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SigmaInteractiveSDK.framework; path = "../../sdk-interactive-mobile-ios/SigmaInteractiveSDK.framework"; sourceTree = ""; };
+ 9BBF1A71288E9572003A6DF2 /* SigmaInteractiveSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SigmaInteractiveSDK.framework; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -51,6 +63,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9BBF1A70288E9564003A6DF2 /* SigmaInteractiveSDK.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -60,7 +73,7 @@
9B7D8F5D27F43D4000C683D4 = {
isa = PBXGroup;
children = (
- 9B4F04B42812ACF40002F0CB /* SigmaInteractiveSDK.framework */,
+ 9BBF1A71288E9572003A6DF2 /* SigmaInteractiveSDK.framework */,
9B85CBF227FAA3A700B7C935 /* AppUtility.swift */,
9B7D8F6827F43D4000C683D4 /* DemoSigmaInteractive */,
9B7D8F6727F43D4000C683D4 /* Products */,
@@ -87,6 +100,11 @@
9B7D8F7427F43D4D00C683D4 /* LaunchScreen.storyboard */,
9B7D8F7727F43D4D00C683D4 /* Info.plist */,
9B7D8F9027F567A300C683D4 /* PlayerViewController.swift */,
+ 9B66464128517FC1005E0399 /* PopupWindow.swift */,
+ 9B6646462852DB23005E0399 /* CodableExtensions.swift */,
+ 9B6646482852DB59005E0399 /* Utility.swift */,
+ 9B66464A2852EBF8005E0399 /* GenerateToken.swift */,
+ 9B66464C2852F1C3005E0399 /* PopupSelect.swift */,
);
path = DemoSigmaInteractive;
sourceTree = "";
@@ -94,6 +112,7 @@
9B7D8F8627F43E1F00C683D4 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 9BBF1A6F288E9564003A6DF2 /* SigmaInteractiveSDK.framework */,
);
name = Frameworks;
sourceTree = "";
@@ -108,13 +127,15 @@
9B7D8F6227F43D4000C683D4 /* Sources */,
9B7D8F6327F43D4000C683D4 /* Frameworks */,
9B7D8F6427F43D4000C683D4 /* Resources */,
- 9B4F0446281276850002F0CB /* Embed Frameworks */,
+ 9BF0591B287420BE005DB1B6 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = DemoSigmaInteractive;
+ packageProductDependencies = (
+ );
productName = DemoSigmaInteractive;
productReference = 9B7D8F6627F43D4000C683D4 /* DemoSigmaInteractive.app */;
productType = "com.apple.product-type.application";
@@ -143,6 +164,8 @@
Base,
);
mainGroup = 9B7D8F5D27F43D4000C683D4;
+ packageReferences = (
+ );
productRefGroup = 9B7D8F6727F43D4000C683D4 /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -171,10 +194,15 @@
buildActionMask = 2147483647;
files = (
9B7D8F6E27F43D4000C683D4 /* ViewController.swift in Sources */,
+ 9B66464B2852EBF8005E0399 /* GenerateToken.swift in Sources */,
9B7D8F9127F567A300C683D4 /* PlayerViewController.swift in Sources */,
9B85CBF327FAA3A700B7C935 /* AppUtility.swift in Sources */,
+ 9B66464D2852F1C3005E0399 /* PopupSelect.swift in Sources */,
9B7D8F6A27F43D4000C683D4 /* AppDelegate.swift in Sources */,
+ 9B6646492852DB59005E0399 /* Utility.swift in Sources */,
+ 9B66464228517FC1005E0399 /* PopupWindow.swift in Sources */,
9B7D8F6C27F43D4000C683D4 /* SceneDelegate.swift in Sources */,
+ 9B6646472852DB23005E0399 /* CodableExtensions.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -323,10 +351,10 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = QDX5365AY6;
- "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64, arm64e, armv7";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
@@ -349,6 +377,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sigma.td.demo.DemoSigmaInteractive;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -360,6 +389,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = QDX5365AY6;
@@ -385,6 +415,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.sigma.td.demo.DemoSigmaInteractive;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.xcworkspace/xcuserdata/phamhai.xcuserdatad/UserInterfaceState.xcuserstate b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.xcworkspace/xcuserdata/phamhai.xcuserdatad/UserInterfaceState.xcuserstate
index 4f3e54c..4a73de5 100644
Binary files a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.xcworkspace/xcuserdata/phamhai.xcuserdatad/UserInterfaceState.xcuserstate and b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/project.xcworkspace/xcuserdata/phamhai.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 5f806de..4435978 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -14,8 +14,8 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "122"
- endingLineNumber = "122"
+ startingLineNumber = "167"
+ endingLineNumber = "167"
landmarkName = "observeValue(forKeyPath:of:change:context:)"
landmarkType = "7">
@@ -30,8 +30,8 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "152"
- endingLineNumber = "152"
+ startingLineNumber = "198"
+ endingLineNumber = "198"
landmarkName = "metadataOutput(_:didOutputTimedMetadataGroups:from:)"
landmarkType = "7">
@@ -46,8 +46,8 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "245"
- endingLineNumber = "245"
+ startingLineNumber = "295"
+ endingLineNumber = "295"
landmarkName = "stopBtnPressed(_:)"
landmarkType = "7">
@@ -62,8 +62,8 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "123"
- endingLineNumber = "123"
+ startingLineNumber = "169"
+ endingLineNumber = "169"
landmarkName = "observeValue(forKeyPath:of:change:context:)"
landmarkType = "7">
@@ -78,8 +78,8 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "137"
- endingLineNumber = "137"
+ startingLineNumber = "183"
+ endingLineNumber = "183"
landmarkName = "observeValue(forKeyPath:of:change:context:)"
landmarkType = "7">
@@ -110,11 +110,123 @@
filePath = "DemoSigmaInteractive/PlayerViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
- startingLineNumber = "118"
- endingLineNumber = "118"
+ startingLineNumber = "143"
+ endingLineNumber = "143"
landmarkName = "goFullscreen()"
landmarkType = "7">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcschemes/xcschememanagement.plist b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcschemes/xcschememanagement.plist
index 1f0f190..4096fe5 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive.xcodeproj/xcuserdata/phamhai.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
DemoSigmaInteractive.xcscheme_^#shared#^_
orderHint
- 2
+ 0
SuppressBuildableAutocreation
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Base.lproj/Main.storyboard b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Base.lproj/Main.storyboard
index 7be26e1..db18dcf 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Base.lproj/Main.storyboard
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Base.lproj/Main.storyboard
@@ -1,8 +1,9 @@
-
+
-
+
+
@@ -12,51 +13,163 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
-
+
@@ -90,11 +210,12 @@
-
+
+
@@ -131,9 +252,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/CodableExtensions.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/CodableExtensions.swift
new file mode 100644
index 0000000..f65b13c
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/CodableExtensions.swift
@@ -0,0 +1,231 @@
+//
+// CodableExtensions.swift
+// DemoSigmaInteractive
+//
+// Created by Pham Hai on 10/06/2022.
+//
+import Foundation
+
+struct JSONCodingKeys: CodingKey {
+ var stringValue: String
+ var intValue: Int?
+
+ init?(stringValue: String) {
+ self.stringValue = stringValue
+ }
+
+ init?(intValue: Int) {
+ self.init(stringValue: "\(intValue)")
+ self.intValue = intValue
+ }
+}
+
+//MARK:- Decoding Extensions
+extension KeyedDecodingContainer {
+ func decode(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any] {
+ let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
+ return try container.decode(type)
+ }
+
+ func decode(_ type: [[String: Any]].Type, forKey key: K) throws -> [[String: Any]] {
+ var container = try self.nestedUnkeyedContainer(forKey: key)
+ if let decodedData = try container.decode([Any].self) as? [[String: Any]] {
+ return decodedData
+ } else {
+ return []
+ }
+ }
+
+ func decodeIfPresent(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any]? {
+ guard contains(key) else {
+ return nil
+ }
+ guard try decodeNil(forKey: key) == false else {
+ return nil
+ }
+ return try decode(type, forKey: key)
+ }
+
+ func decode(_ type: [Any].Type, forKey key: K) throws -> [Any] {
+ var container = try self.nestedUnkeyedContainer(forKey: key)
+ return try container.decode(type)
+ }
+
+ func decodeIfPresent(_ type: [Any].Type, forKey key: K) throws -> [Any]? {
+ guard contains(key) else {
+ return nil
+ }
+ guard try decodeNil(forKey: key) == false else {
+ return nil
+ }
+ return try decode(type, forKey: key)
+ }
+
+ func decode(_ type: [String: Any].Type) throws -> [String: Any] {
+ var dictionary = [String: Any]()
+ for key in allKeys {
+ if let boolValue = try? decode(Bool.self, forKey: key) {
+ dictionary[key.stringValue] = boolValue
+ } else if let stringValue = try? decode(String.self, forKey: key) {
+ dictionary[key.stringValue] = stringValue
+ } else if let intValue = try? decode(Int.self, forKey: key) {
+ dictionary[key.stringValue] = intValue
+ } else if let doubleValue = try? decode(Double.self, forKey: key) {
+ dictionary[key.stringValue] = doubleValue
+ } else if let nestedDictionary = try? decode(Dictionary.self, forKey: key) {
+ dictionary[key.stringValue] = nestedDictionary
+ } else if let nestedArray = try? decode(Array.self, forKey: key) {
+ dictionary[key.stringValue] = nestedArray
+ }
+ }
+ return dictionary
+ }
+}
+
+extension UnkeyedDecodingContainer {
+ mutating func decode(_ type: [Any].Type) throws -> [Any] {
+ var array: [Any] = []
+ while isAtEnd == false {
+ // See if the current value in the JSON array is `null` first and prevent infite recursion with nested arrays.
+ if try decodeNil() {
+ continue
+ } else if let value = try? decode(Bool.self) {
+ array.append(value)
+ } else if let value = try? decode(Double.self) {
+ array.append(value)
+ } else if let value = try? decode(String.self) {
+ array.append(value)
+ } else if let nestedDictionary = try? decode(Dictionary.self) {
+ array.append(nestedDictionary)
+ } else if let nestedArray = try? decode(Array.self) {
+ array.append(nestedArray)
+ }
+ }
+ return array
+ }
+
+ mutating func decode(_ type: [String: Any].Type) throws -> [String: Any] {
+ let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
+ return try nestedContainer.decode(type)
+ }
+}
+
+//MARK:- Encoding Extensions
+extension KeyedEncodingContainer {
+ mutating func encodeIfPresent(_ value: [String: Any]?, forKey key: KeyedEncodingContainer.Key) throws {
+ guard let safeValue = value, !safeValue.isEmpty else {
+ return
+ }
+ var container = self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
+ for item in safeValue {
+ if let val = item.value as? Int {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? String {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Double {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Float {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Bool {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? [Any] {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? [String: Any] {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ }
+ }
+ }
+
+ mutating func encodeIfPresent(_ value: [Any]?, forKey key: KeyedEncodingContainer.Key) throws {
+ guard let safeValue = value else {
+ return
+ }
+ if let val = safeValue as? [Int] {
+ try self.encodeIfPresent(val, forKey: key)
+ } else if let val = safeValue as? [String] {
+ try self.encodeIfPresent(val, forKey: key)
+ } else if let val = safeValue as? [Double] {
+ try self.encodeIfPresent(val, forKey: key)
+ } else if let val = safeValue as? [Float] {
+ try self.encodeIfPresent(val, forKey: key)
+ } else if let val = safeValue as? [Bool] {
+ try self.encodeIfPresent(val, forKey: key)
+ } else if let val = value as? [[String: Any]] {
+ var container = self.nestedUnkeyedContainer(forKey: key)
+ try container.encode(contentsOf: val)
+ }
+ }
+}
+
+extension UnkeyedEncodingContainer {
+ mutating func encode(contentsOf sequence: [[String: Any]]) throws {
+ for dict in sequence {
+ try self.encodeIfPresent(dict)
+ }
+ }
+
+ mutating func encodeIfPresent(_ value: [String: Any]) throws {
+ var container = self.nestedContainer(keyedBy: JSONCodingKeys.self)
+ for item in value {
+ if let val = item.value as? Int {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? String {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Double {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Float {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? Bool {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? [Any] {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ } else if let val = item.value as? [String: Any] {
+ try container.encodeIfPresent(val, forKey: JSONCodingKeys(stringValue: item.key)!)
+ }
+ }
+ }
+}
+
+//MARK:- Extra extensions for managing data easily
+extension Decodable {
+ init?(dictionary: [String: Any]) {
+ do {
+ let data = try JSONSerialization.data(withJSONObject: dictionary, options: .prettyPrinted)
+ if let decodedData = Utility.decode(Self.self, from: data) {
+ self = decodedData
+ } else {
+ return nil
+ }
+ } catch _ {
+ return nil
+ }
+ }
+}
+
+extension Encodable {
+ var dictionary: [String: Any]? {
+ let encoder = JSONEncoder()
+ guard let data = try? encoder.encode(self) else { return nil }
+ return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
+ }
+
+ var prettyJSON: String {
+ dictionary?.prettyJSON ?? "{}"
+ }
+}
+
+extension Dictionary {
+ var prettyJSON: String {
+ do {
+ let jsonData = try JSONSerialization.data(withJSONObject: self, options: [.prettyPrinted])
+ guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
+ print("Can't create string with data.")
+ return "{}"
+ }
+ return jsonString
+ } catch let parseError {
+ print("json serialization error: \(parseError)")
+ return "{}"
+ }
+ }
+}
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/GenerateToken.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/GenerateToken.swift
new file mode 100644
index 0000000..898d3d2
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/GenerateToken.swift
@@ -0,0 +1,137 @@
+//
+// GenerateToken.swift
+// DemoSigmaInteractive
+//
+// Created by Pham Hai on 10/06/2022.
+//
+
+import Foundation
+import CryptoKit
+
+struct DefaultsKeysUser {
+ static let userId = "userId"
+ static let userRole = "userRole"
+ static let token = "token"
+ static let userData = "userData"
+}
+
+extension Data {
+ func urlSafeBase64EncodedString() -> String {
+ return base64EncodedString()
+ .replacingOccurrences(of: "+", with: "-")
+ .replacingOccurrences(of: "/", with: "_")
+ .replacingOccurrences(of: "=", with: "")
+ }
+}
+
+struct Header: Encodable {
+ let alg = "HS256"
+ let typ = "JWT"
+}
+
+struct Payload: Codable {
+ let id: String
+ let exp: Int64
+ let role: String
+ let appId: String
+ let userData: [String: String]?
+}
+
+extension Date {
+ var millisecondsSince1970:Int64 {
+ Int64((self.timeIntervalSince1970 * 1000.0).rounded())
+ }
+
+ init(milliseconds:Int64) {
+ self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000)
+ }
+}
+let tokenFix = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWQiOiJhZG1pbiIsImlzQWRtaW4iOmZhbHNlLCJpYXQiOjE2NDEzNTYyNTl9.WBRTuqhjBvzHTWCSorkVWeGeRcDFZUHzkGekDGtuZqg";
+let apiToken = "https://dev-livestream.gviet.vn/api/interactive/v1/users/gen-token"
+class GenerateToken {
+ var uid: String
+ var userData: [String: Any]
+ var role: String
+
+ init(_ uid:String, _ userData: [String: Any], _ role: String) {
+ self.uid = uid
+ self.userData = userData
+ self.role = role
+ let defaults = UserDefaults.standard
+ defaults.set(uid, forKey: DefaultsKeysUser.userId)
+ defaults.set(userData, forKey: DefaultsKeysUser.userData)
+ defaults.set(role, forKey: DefaultsKeysUser.userRole)
+ }
+// public func genToken() -> String {
+// let secret = "abd89b50-d760-4a97-bb24-0a44881fc04a"
+// let privateKey = SymmetricKey(data: Data(secret.utf8))
+// let headerJSONData = try! JSONEncoder().encode(Header())
+// let headerBase64String = headerJSONData.urlSafeBase64EncodedString()
+// let payloadJSONData = try! JSONEncoder().encode(Payload(id: uid, exp: Date().millisecondsSince1970 + 30*24*3600*1000, role: role, appId: "default-app", userData: userData.count > 0 ? userData : nil))
+// let payloadBase64String = payloadJSONData.urlSafeBase64EncodedString()
+// let toSign = Data((headerBase64String + "." + payloadBase64String).utf8)
+// let signature = HMAC.authenticationCode(for: toSign, using: privateKey)
+// let signatureBase64String = Data(signature).urlSafeBase64EncodedString()
+// let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
+// print("tokenApp=>", token)
+// return token
+// }
+ public func convertDicToJsonString() -> String {
+ let sigmaInteractiveVersion = Bundle.main.object(forInfoDictionaryKey: "SigmaInteractiveVersion") as? String
+ let sigmaInteractiveAppId = Bundle.main.object(forInfoDictionaryKey: "SigmaInteractiveAppId") as? String
+ print("convertDicToJsonString=>", sigmaInteractiveAppId, sigmaInteractiveVersion)
+ var dataGetToken:[String: Any] = [:]
+ dataGetToken["id"] = uid;
+ dataGetToken["role"] = role
+ dataGetToken["appId"] = sigmaInteractiveAppId
+ if userData.count > 0 {
+ dataGetToken["userData"] = userData
+ }
+ var dataStringReturn = ""
+ do {
+ let jsonData = try JSONSerialization.data(withJSONObject: dataGetToken, options: .prettyPrinted)
+ // here "jsonData" is the dictionary encoded in JSON data
+ dataStringReturn = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String
+ } catch {
+ print(error.localizedDescription)
+ }
+ print("DataStringPost=>", dataStringReturn)
+ return dataStringReturn
+ }
+ public func genTokenFromApi() -> String {
+ var token = ""
+ let semaphore = DispatchSemaphore.init(value: 0)
+ let postData = convertDicToJsonString().data(using: .utf8)
+
+ var request = URLRequest(url: URL(string: apiToken)!,timeoutInterval: Double.infinity)
+ request.addValue(tokenFix, forHTTPHeaderField: "authorization")
+ request.addValue("application/json", forHTTPHeaderField: "Content-Type")
+
+ request.httpMethod = "POST"
+ request.httpBody = postData
+ print("postData=>", postData)
+ let task = URLSession.shared.dataTask(with: request) { data, response, error in
+ guard let data = data else {
+ print(String(describing: error))
+ print("error=>", error)
+ semaphore.signal()
+ return
+ }
+ print("data=>", data)
+ do {
+ if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] {
+ guard let tokenServer = json["token"] as? String else { return }
+ print("tokenServer=>", tokenServer)
+ token = tokenServer
+ }
+ } catch{ print("erroMsg") }
+ semaphore.signal()
+ }
+ task.resume()
+ semaphore.wait()
+ let defaults = UserDefaults.standard
+ defaults.set(token, forKey: DefaultsKeysUser.token)
+ print("token=>", token)
+ return token
+ }
+}
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Info.plist b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Info.plist
index dd3c9af..b2c4f4f 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Info.plist
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Info.plist
@@ -21,5 +21,9 @@
+ SigmaInteractiveAppId
+ default-app
+ SigmaInteractiveVersion
+ 3.0.0
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PlayerViewController.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PlayerViewController.swift
index 73878e7..f79f5d6 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PlayerViewController.swift
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PlayerViewController.swift
@@ -10,7 +10,7 @@ import UIKit
import AVFoundation
import AVKit
import SigmaInteractiveSDK
-
+import WebKit
let redirectScheme = "cplp";
let customPlaylistScheme = "cplp";
@@ -19,7 +19,7 @@ let httpScheme = "http";
let badRequestErrorCode = 400;
let redirectErrorCode = 302;
-class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMetadataOutputPushDelegate, AVAssetResourceLoaderDelegate, AVPlayerItemMetadataCollectorPushDelegate {
+class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMetadataOutputPushDelegate, AVAssetResourceLoaderDelegate, AVPlayerItemMetadataCollectorPushDelegate, WKNavigationDelegate {
func metadataCollector(_ metadataCollector: AVPlayerItemMetadataCollector, didCollect metadataGroups: [AVDateRangeMetadataGroup], indexesOfNewGroups: IndexSet, indexesOfModifiedGroups: IndexSet) {
//
@@ -45,6 +45,15 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
print("SigmaJSInterface=>onExitFullScreen")
}
+ func fullReload() {
+ print("SigmaJSInterface=>fullReload")
+ setDataToInteractive(isReload: true)
+ }
+
+ func setSession(_ session: String) {
+ print("SigmaJSInterface=>setSession", session)
+ }
+
var interactiveLink: String = "";
var videoUrl: String = "";
var fullScreenAnimationDuration: TimeInterval {
@@ -58,6 +67,11 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
var playerItem: AVPlayerItem?;
var topSafeArea = 0.0
var bottomSafeArea = 0.0
+ var tokenApp = ""
+ var uid = ""
+ var userRole = ""
+ var userData:[String: Any] = [:]
+ var channelId = ""
var layer: AVPlayerLayer = AVPlayerLayer();
private var videoPlayer: AVPlayer?
@@ -70,6 +84,7 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
print("videoUrl=>", videoUrl);
super.viewDidLoad()
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: []);
+ NotificationCenter.default.addObserver(self,selector: #selector(applicationDidBecomeActive),name: UIApplication.didBecomeActiveNotification, object: nil)
startPlayer();
}
override func viewWillDisappear(_ animated: Bool) {
@@ -79,6 +94,16 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
AppUtility.lockOrientation(.portrait)
+ NotificationCenter.default.removeObserver(self,
+ name: UIApplication.didBecomeActiveNotification, // UIApplication.didBecomeActiveNotification for swift 4.2+
+ object: nil)
+ }
+ @objc func applicationDidBecomeActive() {
+ // handle event
+ print("applicationDidBecomeActive=>", videoPlayer?.rate, videoPlayer?.error)
+ if(videoPlayer != nil) {
+ videoPlayer?.play()
+ }
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator);
@@ -100,10 +125,10 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
func minimizeToFrame() {
UIView.animate(withDuration: fullScreenAnimationDuration) {
let heightVideo = self.widthDevice * (9/16);
- self.layer.frame = CGRect(x: 0, y: (self.heightDevice - heightVideo)/2, width: self.widthDevice, height: heightVideo)
+ self.layer.frame = CGRect(x: 0, y: 0, width: self.widthDevice, height: heightVideo)
self.layer.videoGravity = .resizeAspectFill;
if(self.sigmaInteractive != nil) {
- self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
+ self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice - self.topSafeArea), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
}
}
}
@@ -119,15 +144,36 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
}
}
}
+ func getTokenApp() -> String {
+ return userRole == "guest" ? "" : tokenApp;
+ }
+ func getTokenAppNew() -> String {
+ return userRole == "guest" ? "" : GenerateToken(uid, userData, userRole).genTokenFromApi();
+ }
+ func getDataSendToInteractive(isReload: Bool) -> [String: Any] {
+ var userData: [String: Any] = ["channelId": self.channelId, "panel": true, "overlay": true];
+ userData["token"] = isReload ? getTokenAppNew() : getTokenApp();
+ print("getDataSendToInteractive=>", userData)
+ return userData;
+ }
+ func setDataToInteractive(isReload: Bool) {
+ let dataSend = getDataSendToInteractive(isReload: isReload);
+ if(isReload) {
+ self.sigmaInteractive?.sendUserValue(value: dataSend);
+ } else {
+ self.sigmaInteractive?.setUserValue(value: dataSend);
+ }
+ }
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
+ print("observeValueKeyPath=>", keyPath)
if let player = object as? AVPlayer, player == videoPlayer, keyPath == "status" {
if player.status == .readyToPlay {
+ print("heightDevice=>", self.heightDevice, topSafeArea)
videoPlayer?.play()
let heightVideo = self.widthDevice * (9/16);
- let userData: [String: Any] = ["id": "386", "phone": "0143100004"];
self.sigmaInteractive = SigmaWebview.init(interactiveLink);
- self.sigmaInteractive?.setUserValue(value: userData);
- self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
+ setDataToInteractive(isReload: false)
+ self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice - topSafeArea), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
playerView.addSubview(self.sigmaInteractive!)
self.sigmaInteractive?.setCallBack(sigmaInteractiveCallback: self);
} else if player.status == .failed {
@@ -214,6 +260,7 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
private func startPlayer() {
if let url = URL(string: videoUrl) {
let asset = AVURLAsset(url: url, options: nil);
+ let playerViewController = AVPlayerViewController()
playerItem = AVPlayerItem(asset: asset)
videoPlayer = AVPlayer(playerItem: playerItem)
videoPlayer?.addObserver(self, forKeyPath: "status", options: [], context: nil)
@@ -222,12 +269,15 @@ class PlayerViewController: UIViewController, SigmaJSInterface, AVPlayerItemMeta
guard let self = self else { return }
let seconds = CMTimeGetSeconds(sec)
}
+ playerViewController.player = videoPlayer
+// self.present(playerViewController, animated: true) {
+// playerViewController.player!.play()
+// }
videoPlayer?.volume = 1.0
-
layer = AVPlayerLayer(player: videoPlayer);
layer.backgroundColor = UIColor.white.cgColor
let heightVideo = widthDevice * (9/16);
- layer.frame = CGRect(x: 0, y: (self.heightDevice - heightVideo)/2, width: widthDevice, height: heightVideo)
+ layer.frame = CGRect(x: 0, y: 0, width: widthDevice, height: heightVideo)
layer.videoGravity = .resizeAspectFill
playerView.layer.sublayers?
.filter { $0 is AVPlayerLayer }
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupSelect.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupSelect.swift
new file mode 100644
index 0000000..a874f60
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupSelect.swift
@@ -0,0 +1,211 @@
+//
+// PopupSelect.swift
+// DemoSigmaInteractive
+//
+// Created by Pham Hai on 10/06/2022.
+//
+
+import Foundation
+import UIKit
+
+
+class PopUpWindowSelect: UIViewController {
+ private let popUpWindowView = PopUpWindowSelectView()
+ var callback: (ListFieldType.ListChannel) -> Void
+ init(title: String, text: String, buttontext: String, buttonTextCancel: String, callback: @escaping (ListFieldType.ListChannel) -> Void, selectedChannel: ListFieldType.ListChannel) {
+ self.callback = callback
+ super.init(nibName: nil, bundle: nil)
+ modalTransitionStyle = .crossDissolve
+ modalPresentationStyle = .overFullScreen
+ print("selectedChannel=>", selectedChannel)
+ popUpWindowView.selectedChannel = selectedChannel
+ popUpWindowView.listChannel.selectRow(selectedChannel == .vtv1 ? 0 : selectedChannel == .vtv2 ? 1 : selectedChannel == .vtv3 ? 2 : 3, inComponent: 0, animated: true);
+ popUpWindowView.popupTitle.text = title
+ popUpWindowView.popupButton.setTitle(buttontext, for: .normal)
+ popUpWindowView.popupButton.addTarget(self, action: #selector(onOk), for: .touchUpInside)
+ popUpWindowView.popupButtonCancel.setTitle(buttonTextCancel, for: .normal)
+ popUpWindowView.popupButtonCancel.addTarget(self, action: #selector(dismissView), for: .touchUpInside)
+ view = popUpWindowView
+ }
+
+ required init(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+
+ @objc func onOk(){
+ print("selectedChannel=>", popUpWindowView.listChannel.selectedRow(inComponent: 0))
+ dismissView()
+ let selectedIndex = popUpWindowView.listChannel.selectedRow(inComponent: 0)
+ switch(selectedIndex) {
+ case 0:
+ self.callback(ListFieldType.ListChannel.vtv1)
+ break;
+ case 1:
+ self.callback(ListFieldType.ListChannel.vtv2)
+ break;
+ case 2:
+ self.callback(ListFieldType.ListChannel.vtv3)
+ break;
+ case 3:
+ self.callback(ListFieldType.ListChannel.vtv4)
+ break;
+ default: break;
+ }
+ }
+ @objc func dismissView(){
+ self.dismiss(animated: true, completion: nil)
+ }
+
+}
+
+private class PopUpWindowSelectView: UIView, UIPickerViewDelegate, UIPickerViewDataSource {
+
+ let popupView = UIView(frame: CGRect.zero)
+ let popupTitle = UILabel(frame: CGRect.zero)
+ let popupText = UIView(frame: CGRect.zero)
+ let popupButton = UIButton(frame: CGRect.zero)
+ let popupButtonCancel = UIButton(frame: CGRect.zero)
+ let listChannel = UIPickerView(frame: CGRect(x: 0, y: 0, width: 260, height: 200))
+ var pickerData: [String] = [
+ ListFieldType.ListChannel.vtv1.rawValue,
+ ListFieldType.ListChannel.vtv2.rawValue,
+ ListFieldType.ListChannel.vtv3.rawValue,
+ ListFieldType.ListChannel.vtv4.rawValue,
+ ]
+ let BorderWidth: CGFloat = 2.0
+ var selectedChannel = ListFieldType.ListChannel.vtv1
+
+ init() {
+ super.init(frame: CGRect.zero)
+ listChannel.delegate = self
+ listChannel.dataSource = self
+ listChannel.selectRow(selectedChannel == .vtv1 ? 0 : selectedChannel == .vtv2 ? 1 : selectedChannel == .vtv3 ? 2 : 3, inComponent: 0, animated: false)
+ // Semi-transparent background
+
+ backgroundColor = UIColor.black.withAlphaComponent(0.3)
+
+ // Popup Background
+ popupView.backgroundColor = UIColor(hexString:"#FFFFFF")
+ popupView.layer.borderWidth = BorderWidth
+ popupView.layer.masksToBounds = true
+ popupView.layer.borderColor = UIColor.white.cgColor
+
+ // Popup Title
+ popupTitle.textColor = UIColor.black
+ popupTitle.backgroundColor = UIColor(hexString: "#DDDDDD")
+ popupTitle.layer.masksToBounds = true
+ popupTitle.adjustsFontSizeToFitWidth = true
+ popupTitle.clipsToBounds = true
+ popupTitle.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupTitle.numberOfLines = 1
+ popupTitle.textAlignment = .center
+
+ // Popup Text
+ popupText.backgroundColor = UIColor.white
+ //select type
+ popupText.addSubview(listChannel)
+
+ // Popup Button
+ popupButton.setTitleColor(UIColor.white, for: .normal)
+ popupButton.titleLabel?.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupButton.backgroundColor = UIColor(hexString: "#0000FF")
+
+ popupButtonCancel.setTitleColor(UIColor.white, for: .normal)
+ popupButtonCancel.titleLabel?.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupButtonCancel.backgroundColor = UIColor(hexString: "#FF0000")
+
+ popupView.addSubview(popupTitle)
+// popupView.addSubview(popupText)
+ popupView.addSubview(popupText)
+ popupView.addSubview(popupButton)
+// popupView.addSubview(popupButtonCancel)
+
+ // Add the popupView(box) in the PopUpWindowView (semi-transparent background)
+ addSubview(popupView)
+
+
+ // PopupView constraints
+ popupView.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupView.widthAnchor.constraint(equalToConstant: 293),
+ popupView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
+ popupView.centerXAnchor.constraint(equalTo: self.centerXAnchor)
+ ])
+
+ // PopupTitle constraints
+ popupTitle.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupTitle.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+ popupTitle.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+ popupTitle.topAnchor.constraint(equalTo: popupView.topAnchor, constant: BorderWidth),
+ popupTitle.heightAnchor.constraint(equalToConstant: 55)
+ ])
+
+
+ // PopupText constraints
+ popupText.isUserInteractionEnabled = true
+ popupText.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupText.heightAnchor.constraint(greaterThanOrEqualToConstant: 200),
+ popupText.topAnchor.constraint(equalTo: popupTitle.bottomAnchor, constant: 8),
+ popupText.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: 15),
+ popupText.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -15),
+ popupText.bottomAnchor.constraint(equalTo: popupButton.topAnchor, constant: -8)
+ ])
+
+
+ // PopupButton constraints
+ popupButton.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupButton.heightAnchor.constraint(equalToConstant: 44),
+ popupButton.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+ popupButton.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+ popupButton.bottomAnchor.constraint(equalTo: popupView.bottomAnchor, constant: -BorderWidth)
+ ])
+// popupButtonCancel.translatesAutoresizingMaskIntoConstraints = false
+// NSLayoutConstraint.activate([
+// popupButtonCancel.heightAnchor.constraint(equalToConstant: 44),
+// popupButtonCancel.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+// popupButtonCancel.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+// popupButtonCancel.bottomAnchor.constraint(equalTo: popupView.bottomAnchor, constant: -BorderWidth)
+// ])
+
+ }
+ func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
+ let row = pickerData[row]
+ return row
+ }
+
+ func numberOfComponents(in pickerView: UIPickerView) -> Int {
+ return 1
+ }
+
+ func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
+ return pickerData.count
+ }
+
+ @objc func onTapSegment(_ sender: UISegmentedControl) {
+ print("onTapSegment", sender.selectedSegmentIndex)
+ switch sender.selectedSegmentIndex {
+ case 0:
+ print("Segment 0 is selected")
+ selectedChannel = ListFieldType.ListChannel.vtv1
+ case 1:
+ print("Segment 1 is selected")
+ selectedChannel = ListFieldType.ListChannel.vtv2
+ case 2:
+ print("Segment 2 is selected")
+ selectedChannel = ListFieldType.ListChannel.vtv3
+ case 3:
+ print("Segment 3 is selected")
+ selectedChannel = ListFieldType.ListChannel.vtv4
+ default:
+ break
+ }
+ }
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+}
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupWindow.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupWindow.swift
new file mode 100644
index 0000000..031a7d4
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/PopupWindow.swift
@@ -0,0 +1,227 @@
+//
+// PopupWindow.swift
+// DemoSigmaInteractive
+//
+// Created by Pham Hai on 09/06/2022.
+//
+
+import Foundation
+import UIKit
+
+
+extension UIColor {
+ convenience init(hexString: String, alpha: CGFloat = 1.0) {
+ let hexString: String = hexString.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
+ let scanner = Scanner(string: hexString)
+ if (hexString.hasPrefix("#")) {
+ scanner.scanLocation = 1
+ }
+ var color: UInt32 = 0
+ scanner.scanHexInt32(&color)
+ let mask = 0x000000FF
+ let r = Int(color >> 16) & mask
+ let g = Int(color >> 8) & mask
+ let b = Int(color) & mask
+ let red = CGFloat(r) / 255.0
+ let green = CGFloat(g) / 255.0
+ let blue = CGFloat(b) / 255.0
+ self.init(red:red, green:green, blue:blue, alpha:alpha)
+ }
+ func toHexString() -> String {
+ var r:CGFloat = 0
+ var g:CGFloat = 0
+ var b:CGFloat = 0
+ var a:CGFloat = 0
+ getRed(&r, green: &g, blue: &b, alpha: &a)
+ let rgb:Int = (Int)(r*255)<<16 | (Int)(g*255)<<8 | (Int)(b*255)<<0
+ return String(format:"#%06x", rgb)
+ }
+}
+
+class ListFieldType {
+ enum ListType: String {
+ case boolean
+ case number
+ case string
+ }
+ enum ListBoolean: String {
+ case yes = "true"
+ case no = "false"
+ }
+ enum ListChannel: String {
+ case vtv1, vtv2, vtv3, vtv4
+ }
+}
+
+class PopUpWindow: UIViewController {
+ private let popUpWindowView = PopUpWindowView()
+ var callback: (ListFieldType.ListType) -> Void
+ init(title: String, text: String, buttontext: String, buttonTextCancel: String, callback: @escaping (ListFieldType.ListType) -> Void, selectedType: ListFieldType.ListType) {
+ self.callback = callback
+ super.init(nibName: nil, bundle: nil)
+ modalTransitionStyle = .crossDissolve
+ modalPresentationStyle = .overFullScreen
+
+ popUpWindowView.selectedType = selectedType
+ popUpWindowView.listSelectType.selectedSegmentIndex = selectedType == .string ? 0 : selectedType == .boolean ? 1 : 2;
+ popUpWindowView.popupTitle.text = title
+ popUpWindowView.popupButton.setTitle(buttontext, for: .normal)
+ popUpWindowView.popupButton.addTarget(self, action: #selector(onOk), for: .touchUpInside)
+ popUpWindowView.popupButtonCancel.setTitle(buttonTextCancel, for: .normal)
+ popUpWindowView.popupButtonCancel.addTarget(self, action: #selector(dismissView), for: .touchUpInside)
+ view = popUpWindowView
+ }
+
+ required init(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+
+ @objc func onOk(){
+ dismissView()
+ self.callback(popUpWindowView.selectedType)
+ }
+ @objc func dismissView(){
+ self.dismiss(animated: true, completion: nil)
+ }
+
+}
+
+private class PopUpWindowView: UIView {
+
+ let popupView = UIView(frame: CGRect.zero)
+ let popupTitle = UILabel(frame: CGRect.zero)
+ let popupText = UIView(frame: CGRect.zero)
+ let popupButton = UIButton(frame: CGRect.zero)
+ let popupButtonCancel = UIButton(frame: CGRect.zero)
+ let listFieldType = UIPickerView(frame: CGRect.zero)
+ var pickerData: [String] = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6"]
+ let listSelectType = UISegmentedControl(frame: CGRect(x: 0, y: 11, width: 260, height: 50))
+ let BorderWidth: CGFloat = 2.0
+ var selectedType = ListFieldType.ListType.string
+
+ init() {
+ super.init(frame: CGRect.zero)
+ // Semi-transparent background
+ listSelectType.insertSegment(withTitle: ListFieldType.ListType.string.rawValue, at: 0, animated: true)
+ listSelectType.insertSegment(withTitle: ListFieldType.ListType.boolean.rawValue, at: 1, animated: true)
+ listSelectType.insertSegment(withTitle: ListFieldType.ListType.number.rawValue, at: 2, animated: true)
+ listSelectType.layer.borderWidth = 1;
+ listSelectType.layer.borderColor = UIColor.black.withAlphaComponent(0.3).cgColor
+ listSelectType.isUserInteractionEnabled = true
+ listSelectType.selectedSegmentIndex = selectedType == .string ? 0 : selectedType == .boolean ? 1 : 2;
+ listSelectType.selectedSegmentTintColor = UIColor.green
+ listSelectType.addTarget(self, action: #selector(onTapSegment(_:)), for: .valueChanged)
+
+ backgroundColor = UIColor.black.withAlphaComponent(0.3)
+
+ // Popup Background
+ popupView.backgroundColor = UIColor(hexString:"#FFFFFF")
+ popupView.layer.borderWidth = BorderWidth
+ popupView.layer.masksToBounds = true
+ popupView.layer.borderColor = UIColor.white.cgColor
+
+ // Popup Title
+ popupTitle.textColor = UIColor.black
+ popupTitle.backgroundColor = UIColor(hexString: "#DDDDDD")
+ popupTitle.layer.masksToBounds = true
+ popupTitle.adjustsFontSizeToFitWidth = true
+ popupTitle.clipsToBounds = true
+ popupTitle.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupTitle.numberOfLines = 1
+ popupTitle.textAlignment = .center
+
+ // Popup Text
+ popupText.backgroundColor = UIColor.white
+ //select type
+ popupText.addSubview(listSelectType)
+
+ // Popup Button
+ popupButton.setTitleColor(UIColor.white, for: .normal)
+ popupButton.titleLabel?.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupButton.backgroundColor = UIColor(hexString: "#0000FF")
+
+ popupButtonCancel.setTitleColor(UIColor.white, for: .normal)
+ popupButtonCancel.titleLabel?.font = UIFont.systemFont(ofSize: 23.0, weight: .bold)
+ popupButtonCancel.backgroundColor = UIColor(hexString: "#FF0000")
+
+ popupView.addSubview(popupTitle)
+// popupView.addSubview(popupText)
+ popupView.addSubview(popupText)
+ popupView.addSubview(popupButton)
+// popupView.addSubview(popupButtonCancel)
+
+ // Add the popupView(box) in the PopUpWindowView (semi-transparent background)
+ addSubview(popupView)
+
+
+ // PopupView constraints
+ popupView.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupView.widthAnchor.constraint(equalToConstant: 293),
+ popupView.centerYAnchor.constraint(equalTo: self.centerYAnchor),
+ popupView.centerXAnchor.constraint(equalTo: self.centerXAnchor)
+ ])
+
+ // PopupTitle constraints
+ popupTitle.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupTitle.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+ popupTitle.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+ popupTitle.topAnchor.constraint(equalTo: popupView.topAnchor, constant: BorderWidth),
+ popupTitle.heightAnchor.constraint(equalToConstant: 55)
+ ])
+
+
+ // PopupText constraints
+ popupText.isUserInteractionEnabled = true
+ popupText.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupText.heightAnchor.constraint(greaterThanOrEqualToConstant: 80),
+ popupText.topAnchor.constraint(equalTo: popupTitle.bottomAnchor, constant: 8),
+ popupText.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: 15),
+ popupText.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -15),
+ popupText.bottomAnchor.constraint(equalTo: popupButton.topAnchor, constant: -8)
+ ])
+
+
+ // PopupButton constraints
+ popupButton.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ popupButton.heightAnchor.constraint(equalToConstant: 44),
+ popupButton.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+ popupButton.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+ popupButton.bottomAnchor.constraint(equalTo: popupView.bottomAnchor, constant: -BorderWidth)
+ ])
+
+
+// popupButtonCancel.translatesAutoresizingMaskIntoConstraints = false
+// NSLayoutConstraint.activate([
+// popupButtonCancel.heightAnchor.constraint(equalToConstant: 44),
+// popupButtonCancel.leadingAnchor.constraint(equalTo: popupView.leadingAnchor, constant: BorderWidth),
+// popupButtonCancel.trailingAnchor.constraint(equalTo: popupView.trailingAnchor, constant: -BorderWidth),
+// popupButtonCancel.bottomAnchor.constraint(equalTo: popupView.bottomAnchor, constant: -BorderWidth)
+// ])
+
+ }
+ @objc func onTapSegment(_ sender: UISegmentedControl) {
+ print("onTapSegment", sender.selectedSegmentIndex)
+ switch sender.selectedSegmentIndex {
+ case 0:
+ print("Segment 0 is selected")
+ selectedType = ListFieldType.ListType.string
+ case 1:
+ print("Segment 1 is selected")
+ selectedType = ListFieldType.ListType.boolean
+ case 2:
+ print("Segment 2 is selected")
+ selectedType = ListFieldType.ListType.number
+ default:
+ break
+ }
+ }
+ required init?(coder aDecoder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+}
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Utility.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Utility.swift
new file mode 100644
index 0000000..0060696
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/Utility.swift
@@ -0,0 +1,30 @@
+//
+// Utility.swift
+// DemoSigmaInteractive
+//
+// Created by Pham Hai on 10/06/2022.
+//
+import Foundation
+
+class Utility {
+ static func decode(_ decodable: T.Type, from data: Data) -> T? where T: Decodable {
+ var decodedData: T?
+ do {
+ decodedData = try JSONDecoder().decode(T.self, from: data)
+ } catch DecodingError.dataCorrupted(let context) {
+ print(context)
+ } catch DecodingError.keyNotFound(let key, let context) {
+ print("Key '\(key)' not found:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch DecodingError.valueNotFound(let value, let context) {
+ print("Value '\(value)' not found:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch DecodingError.typeMismatch(let type, let context) {
+ print("Type '\(type)' mismatch:", context.debugDescription)
+ print("codingPath:", context.codingPath)
+ } catch {
+ print("error: ", error)
+ }
+ return decodedData
+ }
+}
diff --git a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/ViewController.swift b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/ViewController.swift
index b9f3657..008d8bb 100644
--- a/DemoSigmaInteractiveIOS/DemoSigmaInteractive/ViewController.swift
+++ b/DemoSigmaInteractiveIOS/DemoSigmaInteractive/ViewController.swift
@@ -6,25 +6,103 @@
//
import UIKit
+import CryptoKit
-class ViewController: UIViewController {
+extension UIViewController {
+ func hideKeyboardWhenTappedAround() {
+ let tap = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
+ tap.cancelsTouchesInView = false
+ view.addGestureRecognizer(tap)
+ }
+
+ @objc func dismissKeyboard() {
+ view.endEditing(true)
+ }
+}
+
+let baseUrlChannel = "https://dev-livestream.gviet.vn/manifest/"
+
+let dataChannel:[String: String] = [
+ ListFieldType.ListChannel.vtv1.rawValue: baseUrlChannel + "VTV1-PACKAGE/master.m3u8",
+ ListFieldType.ListChannel.vtv2.rawValue: baseUrlChannel + "VTV2-PACKAGE/master.m3u8",
+ ListFieldType.ListChannel.vtv3.rawValue: baseUrlChannel + "VTV3-PACKAGE/master.m3u8",
+ ListFieldType.ListChannel.vtv4.rawValue: baseUrlChannel + "VTV4/master.m3u8"]
+
+let dataChannelId:[String: String] = [
+ ListFieldType.ListChannel.vtv1.rawValue: "c9c2ebfb-2887-4de6-aec4-0a30aa848915",
+ ListFieldType.ListChannel.vtv2.rawValue: "32a55ed3-4ee1-42f8-819a-407b54a39923",
+ ListFieldType.ListChannel.vtv3.rawValue: "60346597-8ed9-48de-bd4d-8546d0070c7c",
+ ListFieldType.ListChannel.vtv4.rawValue: "22e1fdb6-8d10-4193-8411-562c7104aa2b"]
+
+class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet weak var txtInteractiveLink: UITextView!
@IBOutlet weak var txtVideoUrl: UITextView!
@IBOutlet weak var btnOpenInteractive: UIButton!
+ @IBOutlet weak var btnOpenWithOldConfig: UIButton!
@IBOutlet weak var txtError: UILabel!
+ @IBOutlet weak var txtUid: UITextView!
+ @IBOutlet weak var viewUserData: UIView!
+ @IBOutlet weak var btnAddFieldUserData: UIButton!
+ @IBOutlet weak var scrollView: UIScrollView!
+ @IBOutlet weak var listUserType: UISegmentedControl!
+ @IBOutlet weak var btnGetChannel: UIButton!
+
var topSafeArea = 0.0
var bottomSafeArea = 0.0
+ var typeField = ListFieldType.ListType.string
+ var channel = ListFieldType.ListChannel.vtv1
+ let txtBorderColor: CGColor = UIColor.gray.cgColor;
+ let txtBorderRadius: CGFloat = 5.0, txtBorderWidth:CGFloat = 1.0;
+ let fieldKeyId = "key-"
+ let fieldValueId = "value-"
+ let fieldUserValueContainer = "user-"
+ var userDataValue: [[String: Any]] = []
+ let heightOfBtnDeleteField = 40.0
+ let widthOfBtnDeleteField = 100.0
+ let heightOfInPutField = 50.0
+ let heightOfLabelField = 50.0
+ let heightOfPaddingOfBottomField = 10.0
+ let paddingInput = 5.0
+ var heightOfFieldUserValue = 150.0
+
override func viewDidLoad() {
- let txtBorderColor: CGColor = UIColor.gray.cgColor;
- let txtBorderRadius: CGFloat = 5.0, txtBorderWidth:CGFloat = 1.0;
+ heightOfFieldUserValue = heightOfLabelField + heightOfInPutField + heightOfBtnDeleteField + heightOfPaddingOfBottomField;
txtInteractiveLink.layer.borderWidth = txtBorderWidth;
txtInteractiveLink.layer.borderColor = txtBorderColor;
txtInteractiveLink.layer.cornerRadius = txtBorderRadius;
txtVideoUrl.layer.borderWidth = txtBorderWidth;
txtVideoUrl.layer.borderColor = txtBorderColor;
txtVideoUrl.layer.cornerRadius = txtBorderRadius;
+ txtVideoUrl.text = dataChannel[channel.rawValue]
+ txtUid.layer.borderWidth = txtBorderWidth;
+ txtUid.layer.borderColor = txtBorderColor;
+ txtUid.layer.cornerRadius = txtBorderRadius;
+ txtUid.textContainerInset = UIEdgeInsets(top: 15, left: 4, bottom: 8, right: 4);
+ let tokenCache = getTokenCache()
+ let idCache = getIdCache()
+ let roleCache = getRoleCache()
+ if(tokenCache.count > 0 && idCache.count > 0 && roleCache.count > 0) {
+ txtUid.text = idCache
+// btnOpenWithOldConfig.isEnabled = true;
+// btnOpenWithOldConfig.isHidden = false;
+ listUserType.selectedSegmentIndex = getIndexUserRole(roleCache)
+ } else {
+// btnOpenWithOldConfig.isEnabled = false;
+// btnOpenWithOldConfig.isHidden = true;
+ }
super.viewDidLoad()
+ let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard));
+
+ //Uncomment the line below if you want the tap not not interfere and cancel other interactions.
+ //tap.cancelsTouchesInView = false
+
+ view.addGestureRecognizer(tap)
+ scrollView.contentSize = CGSize(width: self.scrollView.bounds.width, height: self.view.bounds.height + 100);
+ }
+ @objc override func dismissKeyboard() {
+ //Causes the view (or one of its embedded text fields) to resign the first responder status.
+ view.endEditing(true)
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
@@ -47,8 +125,77 @@ class ViewController: UIViewController {
super.viewWillDisappear(animated)
AppUtility.lockOrientation(.all)
}
+ func getTokenCache() -> String {
+ let defaults = UserDefaults.standard
+ if let tokenCache = defaults.string(forKey: DefaultsKeysUser.token) {
+ print("dataSession=>2", tokenCache)
+ return tokenCache
+ }
+ return ""
+ }
+ func getRoleCache() -> String {
+ let defaults = UserDefaults.standard
+ if let roleCache = defaults.string(forKey: DefaultsKeysUser.userRole) {
+ print("roleCache=>2", roleCache)
+ return roleCache
+ }
+ return ""
+ }
+ func getIdCache() -> String {
+ let defaults = UserDefaults.standard
+ if let idCache = defaults.string(forKey: DefaultsKeysUser.userId) {
+ print("idCache=>2", idCache)
+ return idCache
+ }
+ return ""
+ }
+ func getUserDataCache() -> [String: Any] {
+ let defaults = UserDefaults.standard
+ if let userDataCache = defaults.dictionary(forKey: DefaultsKeysUser.userData) {
+ print("userDataCache=>2", userDataCache)
+ return userDataCache
+ }
+ return [:]
+ }
+ @IBAction func openInteractiveWithOldConfig(_ sender: Any) {
+ print("open interactive=>", txtUid.isAccessibilityElement);
+ for itemFieldUser in userDataValue {
+ print("itemFieldUser=>", itemFieldUser)
+ }
+ let uidCache = getIdCache()
+ let roleCache = getRoleCache()
+ let userDataCache = getUserDataCache()
+ let token = getTokenCache()
+ let interactiveLink = txtInteractiveLink.text!, videoUrl = txtVideoUrl.text!;
+ let isEmptyInteractive = interactiveLink.trimmingCharacters(in: .whitespacesAndNewlines).count == 0 || (!interactiveLink.hasPrefix("http://") && !interactiveLink.hasPrefix("https://"));
+ let isEmptyVideoUrl = videoUrl.trimmingCharacters(in: .whitespacesAndNewlines).count == 0 || (!videoUrl.hasPrefix("http://") && !videoUrl.hasPrefix("https://"));
+ if(isEmptyInteractive || isEmptyVideoUrl) {
+ txtError.text = "Lỗi nhập " + (isEmptyInteractive ? "link interactive" : "link video");
+ } else {
+ txtError.text = "";
+ self.view.endEditing(true);
+ let story = UIStoryboard(name: "Main", bundle: nil);
+ let controller = story.instantiateViewController(withIdentifier: "demoPlayer") as! PlayerViewController;
+// let ViewController = ViewController(nibName: "PlayerViewController", bundle: nil);
+ controller.interactiveLink = interactiveLink;
+ controller.videoUrl = videoUrl;
+ controller.bottomSafeArea = bottomSafeArea;
+ controller.topSafeArea = topSafeArea
+ controller.tokenApp = token
+ controller.userRole = roleCache
+ controller.uid = uidCache
+ controller.userData = userDataCache
+ controller.channelId = dataChannelId[channel.rawValue]!
+ self.navigationController?.pushViewController(controller, animated: true);
+// self.present(controller, animated: true, completion: nil);
+ }
+ }
@IBAction func openInteractive(_ sender: UIButton) {
- print("open interactive=>", txtInteractiveLink.text!, txtVideoUrl.text!);
+ print("open interactive=>", txtUid.isAccessibilityElement);
+ for itemFieldUser in userDataValue {
+ print("itemFieldUser=>", itemFieldUser)
+ }
+ let token = getToken()
let interactiveLink = txtInteractiveLink.text!, videoUrl = txtVideoUrl.text!;
let isEmptyInteractive = interactiveLink.trimmingCharacters(in: .whitespacesAndNewlines).count == 0 || (!interactiveLink.hasPrefix("http://") && !interactiveLink.hasPrefix("https://"));
let isEmptyVideoUrl = videoUrl.trimmingCharacters(in: .whitespacesAndNewlines).count == 0 || (!videoUrl.hasPrefix("http://") && !videoUrl.hasPrefix("https://"));
@@ -64,8 +211,262 @@ class ViewController: UIViewController {
controller.videoUrl = videoUrl;
controller.bottomSafeArea = bottomSafeArea;
controller.topSafeArea = topSafeArea
+ controller.tokenApp = token
+ controller.userRole = getUserRole()
+ controller.uid = getUid()
+ controller.userData = getUserData()
+ controller.channelId = dataChannelId[channel.rawValue]!
self.navigationController?.pushViewController(controller, animated: true);
// self.present(controller, animated: true, completion: nil);
}
}
+ func getUserRole() -> String {
+ let selectedRoleIndex = listUserType.selectedSegmentIndex
+ var userRole = "admin"
+ switch(selectedRoleIndex) {
+ case 0:
+ break;
+ case 1:
+ userRole = "user"
+ break;
+ case 2:
+ userRole = "guest"
+ break;
+ default: break
+ }
+ return userRole
+ }
+ func getIndexUserRole(_ role: String) -> Int {
+ let selectedRoleIndex = listUserType.selectedSegmentIndex
+ var indexRole = 0
+ switch(role) {
+ case "admin":
+ indexRole = 0
+ break;
+ case "user":
+ indexRole = 1
+ break;
+ case "guest":
+ indexRole = 2
+ break;
+ default: break
+ }
+ return indexRole
+ }
+ func getUid() -> String {
+ return txtUid.text!;
+ }
+ func getUserData() -> [String: Any] {
+ var formatUserData:[String: Any] = [:]
+ for itemFieldUser in userDataValue {
+ let keyData: String = itemFieldUser["key"] as! String ?? ""
+ let valueData: Any = itemFieldUser["value"]
+ let typeData: String = itemFieldUser["type"] as! String ?? ""
+ if(keyData.count > 0 && typeData.count > 0) {
+ switch(typeData) {
+ case ListFieldType.ListType.boolean.rawValue:
+ formatUserData[keyData] = valueData
+ break;
+ case ListFieldType.ListType.number.rawValue:
+ formatUserData[keyData] = (valueData as! NSString).integerValue
+ break;
+ default:
+ formatUserData[keyData] = valueData
+ break;
+ }
+ }
+ }
+ return formatUserData
+ }
+ func getToken() -> String {
+ var dataGetToken:[String: Any] = [:]
+ dataGetToken["id"] = getUid()
+ dataGetToken["role"] = getUserRole()
+ dataGetToken["appId"] = "default-app"
+ if(getUserRole() == "guest") {
+ let defaults = UserDefaults.standard
+ defaults.set("", forKey: DefaultsKeysUser.token)
+ }
+ return getUserRole() == "guest" ? "" : GenerateToken(getUid(), getUserData(), getUserRole()).genTokenFromApi()
+ }
+ @objc func deleteUserValueField(_ sender: UIButton?) {
+ print("delete=>", sender?.tag)
+ var subviewDelete:UIView
+ var indexRemove = 0
+ var isRemove = false
+ for subview in self.viewUserData.subviews {
+ print("subviewTag=>", subview.tag)
+ if(subview.tag == sender?.tag) {
+ isRemove = true
+ subviewDelete = subview
+ subview.removeFromSuperview()
+ self.viewUserData.frame = CGRect(x: self.viewUserData.frame.origin.x, y: self.viewUserData.frame.origin.y, width: self.viewUserData.frame.width, height: max(50, self.viewUserData.frame.height - heightOfFieldUserValue))
+ scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: scrollView.contentSize.height - heightOfFieldUserValue)
+
+ btnAddFieldUserData.frame = CGRect(x: btnAddFieldUserData.frame.origin.x, y: self.viewUserData.frame.origin.y + self.viewUserData.frame.height + 10, width: btnAddFieldUserData.bounds.width, height: btnAddFieldUserData.bounds.height)
+ } else if(subview.tag > sender!.tag) {
+ subview.frame = CGRect(x: subview.frame.origin.x, y: subview.frame.origin.y - heightOfFieldUserValue, width: subview.frame.width, height: subview.frame.height)
+ }
+ if(!isRemove) {
+ indexRemove += 1
+ }
+ }
+ print("indexRemove=>", indexRemove)
+ userDataValue.remove(at: indexRemove)
+ }
+ func getViewFieldUser(positionY y: Double) -> UIView {
+ let keyTag = Date().millisecondsSince1970
+ let btnDelete:UIButton = UIButton(frame: CGRect(x: (self.viewUserData.frame.width / 2.0) - (widthOfBtnDeleteField/2), y: heightOfLabelField + heightOfInPutField + heightOfPaddingOfBottomField, width: widthOfBtnDeleteField, height: heightOfBtnDeleteField))
+ btnDelete.isAccessibilityElement = true
+ btnDelete.backgroundColor = UIColor.red
+ btnDelete.setTitle("Remove", for: .normal)
+ btnDelete.setTitleColor(UIColor.white, for: .normal)
+ btnDelete.titleLabel?.font = UIFont.systemFont(ofSize: 15.0, weight: .bold)
+ btnDelete.layer.cornerRadius = 5
+
+ let allSubviews = viewUserData.subviews.count;
+ btnDelete.accessibilityIdentifier = "btnDelete-" + String(allSubviews)
+ btnDelete.tag = Int(keyTag)
+ btnDelete.addTarget(self, action: #selector(deleteUserValueField), for: UIButton.Event.touchUpInside)
+ let fieldUserView: UIView = UIView(frame: CGRect(x: 0, y: y, width: self.viewUserData.frame.width, height: Double(heightOfFieldUserValue)));
+ //for key view
+ let fieldUserKeyView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: Double(self.viewUserData.frame.width/2), height: Double(heightOfInPutField + heightOfLabelField)));
+ let labelKey: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.viewUserData.frame.width/2.0, height: heightOfLabelField));
+ labelKey.text = "Key";
+ let uiTextViewKey: UITextView = UITextView(frame: CGRect(x: 0, y: heightOfInPutField, width: self.viewUserData.frame.width/2.0 - paddingInput, height: heightOfInPutField));
+ uiTextViewKey.layer.borderWidth = txtBorderWidth;
+ uiTextViewKey.layer.borderColor = txtBorderColor;
+ uiTextViewKey.layer.cornerRadius = txtBorderRadius;
+ uiTextViewKey.isAccessibilityElement = true
+ uiTextViewKey.delegate = self
+ uiTextViewKey.accessibilityIdentifier = fieldKeyId + String(keyTag)
+ fieldUserKeyView.addSubview(labelKey);
+ fieldUserKeyView.addSubview(uiTextViewKey);
+ fieldUserView.addSubview(fieldUserKeyView)
+ //for value view
+ let fieldUserValueView: UIView = UIView(frame: CGRect(x: Double(self.viewUserData.frame.width / 2), y: 0, width: Double( self.viewUserData.frame.width/2), height: Double(heightOfLabelField + heightOfInPutField)));
+ let labelValue: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.viewUserData.frame.width/2.0, height: heightOfLabelField));
+ labelValue.text = "Value";
+ fieldUserValueView.addSubview(labelValue);
+ switch(typeField) {
+ case .number, .string:
+ //for value view
+ let uiTextViewValue: UITextView = UITextView(frame: CGRect(x: 0, y: heightOfInPutField, width: self.viewUserData.frame.width/2.0, height: heightOfInPutField));
+ uiTextViewValue.layer.borderWidth = txtBorderWidth;
+ uiTextViewValue.layer.borderColor = txtBorderColor;
+ uiTextViewValue.layer.cornerRadius = txtBorderRadius;
+ uiTextViewValue.isAccessibilityElement = true
+ uiTextViewValue.accessibilityIdentifier = fieldValueId + String(keyTag)
+ uiTextViewValue.delegate = self
+ fieldUserValueView.addSubview(uiTextViewValue);
+ fieldUserView.addSubview(fieldUserValueView)
+ userDataValue.append(["key": "", "value": "", "type": typeField.rawValue, "tag": String(keyTag)])
+ break;
+ case .boolean:
+ let listSelectBoolean: UISegmentedControl = UISegmentedControl(frame: CGRect(x: 0, y: heightOfInPutField, width: self.viewUserData.frame.width/2.0, height: heightOfInPutField));
+ listSelectBoolean.insertSegment(withTitle: ListFieldType.ListBoolean.yes.rawValue, at: 0, animated: true)
+ listSelectBoolean.insertSegment(withTitle: ListFieldType.ListBoolean.no.rawValue, at: 1, animated: true)
+ listSelectBoolean.layer.borderWidth = 1;
+ listSelectBoolean.layer.borderColor = UIColor.black.withAlphaComponent(0.3).cgColor
+ listSelectBoolean.isUserInteractionEnabled = true
+ listSelectBoolean.selectedSegmentIndex = 0
+ listSelectBoolean.selectedSegmentTintColor = UIColor.green
+ listSelectBoolean.isAccessibilityElement = true
+ listSelectBoolean.accessibilityIdentifier = fieldValueId + String(keyTag)
+ listSelectBoolean.addTarget(self, action: #selector(onTapSegment(_:)), for: .valueChanged)
+ listSelectBoolean.tag = Int(keyTag)
+ print("fieldValueId=>", listSelectBoolean.accessibilityIdentifier)
+ fieldUserValueView.addSubview(listSelectBoolean);
+ fieldUserView.addSubview(fieldUserValueView)
+ userDataValue.append(["key": "", "value": true, "type": typeField.rawValue, "tag": String(keyTag)])
+ break;
+ default: break
+ }
+ fieldUserView.addSubview(btnDelete)
+ fieldUserView.isAccessibilityElement = true
+ fieldUserView.accessibilityIdentifier = fieldUserValueContainer + String(keyTag)
+ fieldUserView.tag = Int(keyTag)
+ return fieldUserView;
+ }
+ @objc func onTapSegment(_ sender: UISegmentedControl) {
+ print("onTapSegment", sender.selectedSegmentIndex)
+ let arrKey = sender.accessibilityIdentifier!.components(separatedBy: "-")
+ print("arrKey", arrKey)
+ if arrKey.count == 2 {
+ let index: String = arrKey[1]
+ let keySet: String = arrKey[0]
+ var indexNumber = 0
+ var isIndexChange = false
+ for itemUserField in userDataValue {
+ if(itemUserField["tag"] as! String == index) {
+ isIndexChange = true
+ }
+ if(!isIndexChange) {
+ indexNumber += 1
+ }
+ }
+ print("indexNumber=>", indexNumber)
+ userDataValue[indexNumber][keySet] = sender.selectedSegmentIndex == 0
+ }
+ }
+ func textViewDidChange(_ textView: UITextView) {
+ print("textViewDidChange=>", textView.accessibilityIdentifier!, textView.text)
+ let arrKey = textView.accessibilityIdentifier!.components(separatedBy: "-")
+ print("arrKey", arrKey)
+ if arrKey.count == 2 {
+ let index: String = arrKey[1]
+ let keySet: String = arrKey[0]
+ var indexNumber = 0
+ var isIndexChange = false
+ for itemUserField in userDataValue {
+ if(itemUserField["tag"] as! String == index) {
+ isIndexChange = true
+ }
+ if(!isIndexChange) {
+ indexNumber += 1
+ }
+ }
+ print("indexNumber=>", indexNumber)
+ userDataValue[indexNumber][keySet] = textView.text!
+ }
+ }
+ func setTypeField(fieldType type: ListFieldType.ListType) {
+ typeField = type
+ print("typeField=>", typeField);
+ let allSubviews = viewUserData.subviews.count;
+ print("allSubviews=>", allSubviews);
+ switch(type) {
+ case .number, .string, .boolean:
+ self.viewUserData.addSubview(getViewFieldUser(positionY: Double(allSubviews) * (heightOfFieldUserValue)));
+ self.viewUserData.frame = CGRect(x: self.viewUserData.frame.origin.x, y: self.viewUserData.frame.origin.y, width: self.viewUserData.frame.width, height: self.viewUserData.frame.height + (allSubviews > 0 ? heightOfFieldUserValue : heightOfFieldUserValue - 50))
+ btnAddFieldUserData.frame = CGRect(x: btnAddFieldUserData.frame.origin.x, y: self.viewUserData.frame.origin.y + self.viewUserData.frame.height + 10, width: btnAddFieldUserData.bounds.width, height: btnAddFieldUserData.bounds.height)
+ scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: scrollView.contentSize.height + heightOfFieldUserValue)
+ break;
+ default: break
+ }
+ let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
+ scrollView.setContentOffset(bottomOffset, animated: true)
+ }
+ func setChannel(channel id: ListFieldType.ListChannel) {
+ print("setChannel=>", id)
+ channel = id
+ switch(id) {
+ case .vtv1, .vtv2, .vtv3, .vtv4:
+ txtVideoUrl.text = dataChannel[id.rawValue]
+ break;
+ default: break
+ }
+ }
+ @IBAction func onAddUserDataField(_ sender: Any) {
+ var popUpWindow: PopUpWindow!
+ popUpWindow = PopUpWindow(title: "Select field type", text: "Please select field type", buttontext: "OK", buttonTextCancel: "Cancel", callback: setTypeField, selectedType: typeField)
+ self.present(popUpWindow, animated: true, completion: nil)
+
+ }
+ @IBAction func onGetChannel(_ sender: Any) {
+ print("onGetChannel")
+ var popUpWindow: PopUpWindowSelect!
+ popUpWindow = PopUpWindowSelect(title: "Select Channel", text: "Please select channel", buttontext: "OK", buttonTextCancel: "Cancel", callback: setChannel, selectedChannel: channel)
+ self.present(popUpWindow, animated: true, completion: nil)
+ }
}
diff --git a/DemoSigmaInteractiveIOS/README.md b/DemoSigmaInteractiveIOS/README.md
index 8cb45b6..3d326ff 100644
--- a/DemoSigmaInteractiveIOS/README.md
+++ b/DemoSigmaInteractiveIOS/README.md
@@ -6,7 +6,7 @@
Thêm file [SigmaInteractiveSDK.framework](https://github.com/phamngochai123/sigma-interactive-sdk-example/tree/mobile-ios/SigmaInteractiveSDK.framework) vào project.
-Project -> app target -> General -> Embedded Binaries
+Project -> app target -> Build Phases -> Embedded Binaries

@@ -16,25 +16,31 @@ Project -> app target -> General -> Embedded Binaries

-### II. Sử dụng
+### II. Thêm khai báo appId và version sdk interactive
-1. Thêm SigmaInteractive sdk vào project (mục **I**).
+1. Mở file Info.plist
+2. Thêm các thành phần `string` có tên là SigmaInteractiveAppId và SigmaInteractiveVersion. Sau đó đặt những giá trị này thành ID và version của sdk interactive ( sẽ được gửi riêng khi đối tác tích hợp ). Ví dụ: nếu sdk có ID ứng dụng là `default-app` và version là `3.0.0` thì mã sẽ có dạng như sau:
+ ```swift
+ SigmaInteractiveAppId
+ default-app
+ SigmaInteractiveVersion
+ 3.0.0
+ ```
-2. Import SigmaInteractiveSDK vào file:
+### III. Sử dụng
+
+1. Thêm SigmaInteractive sdk vào project (mục **I**).
+2. Import SigmaInteractiveSDK vào file:
```swift
import SigmaInteractiveSDK
```
-
3. Tạo biến sigmaInteractive type SigmaWebview thể hiện cho view tương tác.
```swift
var sigmaInteractive: SigmaWebview?;
```
-
-
-
-4. Thêm sự kiện lắng nghe khi id3 bắt đầu parse để gửi dữ liệu cho sdk tương tác
+4. Thêm sự kiện lắng nghe khi id3 bắt đầu parse để gửi dữ liệu cho sdk tương tác ( bắt buộc nếu hiển thị overlay )
```swift
//create function metadataOutput
@@ -48,7 +54,7 @@ Project -> app target -> General -> Embedded Binaries
}
}
}
-
+
private func startPlayer() {
...
if let url = URL(string: videoUrl) {
@@ -63,10 +69,16 @@ Project -> app target -> General -> Embedded Binaries
}
}
```
+5. Mở view tương tác, set dữ liệu để gửi cho sdk interactive (bắt buộc), set callback để bắt sự kiện view tương tác khi player bắt đầu play.
+ dữ liệu bao gồm:
-5. Mở view tương tác, set dữ liệu user (bắt buộc), set callback để bắt sự kiện view tương tác khi player bắt đầu play.
+ * token: token app ( string )
+ * channelId: id của kênh đang xem ( string )
+ * overlay: bật/tắt overlay (boolean, bật-true, tắt false). Nếu bật thì bắt buộc phải thêm sự kiện như mục 4
+ * panel: bật/tắt panel (boolean, bật-true, tắt-false)
- *Lưu ý: callback implement SigmaJSInterface
+ *Lưu ý: callback implement SigmaJSInterface.
+ Khởi tạo view tương tác: `SigmaWebview.init(interactiveLink);`
```swift
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
@@ -74,16 +86,12 @@ Project -> app target -> General -> Embedded Binaries
if player.status == .readyToPlay {
videoPlayer?.play()
let heightVideo = self.widthDevice * (9/16);
- let userData: [String: Any] = ["id": "386", "phone": "0143100004"];
- //khởi tạo view tương tác
+ // Khởi tạo view tương tác
self.sigmaInteractive = SigmaWebview.init(interactiveLink);
- //set dữ liệu user
- self.sigmaInteractive?.setUserValue(value: userData);
- //set vị trí hiển thị, kích thước của view tương tác và vị trí so với view tương tác, kích thước của view player
- self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
- // hiển thị view tương tác
+ //create and set data để gửi cho sdk khi nhận được sự kiện onReady
+ setDataToInteractive(isReload: false)
+ self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), height: Int(self.heightDevice - topSafeArea), xPlayer: 0, yPlayer: 0, widthPlayer: Int(self.widthDevice), heightPlayer: Int(heightVideo))
playerView.addSubview(self.sigmaInteractive!)
- //set callback để bắt các sự kiện view tương tác gọi
self.sigmaInteractive?.setCallBack(sigmaInteractiveCallback: self);
} else if player.status == .failed {
stopBtnPressed(UIButton())
@@ -92,9 +100,6 @@ Project -> app target -> General -> Embedded Binaries
...
}
```
-
-
-
6. Bắt sự kiện lắng nghe khi id3 trả ra đúng thời điểm hẹn giờ để gửi dữ liệu cho sdk tương tác
```swift
@@ -116,19 +121,42 @@ Project -> app target -> General -> Embedded Binaries
}
```
-- #### SigmaWebview
+#### SigmaWebview
- #### - setUserValue - set dữ liệu user dạng json string
-
- ```swift
- self.sigmaInteractive?.setUserValue(value: userData);
- ```
-
+#### - setUserValue - set dữ liệu user dạng Dictionary để gửi cho sdk khi nhận được sự kiện onReady
+
+#### - sendUserValue - gửi dữ liệu user cho sdk interactive
+
+```swift
+self.sigmaInteractive?.setUserValue(value: userData);
+
+func getDataSendToInteractive(isReload: Bool) -> [String: Any] {
+ //data send to interactive. on-off panel, overlay (on-true, off-false)
+ var userData: [String: Any] = ["channelId": self.channelId, "panel": true, "overlay": true];
+ userData["token"] = isReload ? getTokenAppNew() : getTokenApp();
+ return userData;
+}
+
+func setDataToInteractive(isReload: Bool) {
+ let dataSend = getDataSendToInteractive(isReload: isReload);
+ if(isReload) {
+ self.sigmaInteractive?.sendUserValue(value: dataSend);
+ } else {
+ self.sigmaInteractive?.setUserValue(value: dataSend);
+ }
+}
+```
#### - setCallBack - set callback để nhận sự kiện view tương tác gọi
+#### *Lưu ý: Trong callback có hàm fullReload. Khi hàm này được gọi thì client cần gửi lại data cho hệ thống interactive
+
```swift
self.sigmaInteractive?.setCallBack(sigmaInteractiveCallback: self);
+
+func fullReload() {
+ setDataToInteractive(isReload: true)
+ }
```
#### - sendID3TagInstant - gửi id3 instant cho sdk tương tác
@@ -142,19 +170,12 @@ self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), heigh
```
- `x`: Vị trí muốn đặt view tương tác theo trục x.
-
- `y`: Vị trí muốn đặt view tương tác theo trục y.
-
- `width`: Chiều rộng của view tương tác.
-
- `height`: Chiều cao của view tương tác.
-
- `widthPlayer`: Chiều rộng của player.
-
- `heightPlayer`: Chiều caocủa player.
-
- `xPlayer`: Vị trí player theo trục x.
-
- `yPlayer`: Vị trí player theo trục y.
```swift
@@ -171,4 +192,3 @@ self.sigmaInteractive!.setLayout(x: 0, y: 0, width: Int(self.widthDevice), heigh
}
}
```
-
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/.DS_Store b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/.DS_Store
deleted file mode 100644
index 0bba62b..0000000
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/.DS_Store and /dev/null differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Headers/SigmaInteractiveSDK-Swift.h b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Headers/SigmaInteractiveSDK-Swift.h
index bf23d20..852b8a1 100644
--- a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Headers/SigmaInteractiveSDK-Swift.h
+++ b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Headers/SigmaInteractiveSDK-Swift.h
@@ -237,7 +237,6 @@ SWIFT_CLASS("_TtC19SigmaInteractiveSDK12SigmaWebview")
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder SWIFT_UNAVAILABLE;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent * _Nullable)event SWIFT_WARN_UNUSED_RESULT;
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext * _Nonnull)context SWIFT_WARN_UNUSED_RESULT;
-- (BOOL)becomeFirstResponder SWIFT_WARN_UNUSED_RESULT;
@property (nonatomic, readonly) UIEdgeInsets safeAreaInsets;
- (nonnull instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration * _Nonnull)configuration SWIFT_UNAVAILABLE;
@end
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/.DS_Store b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/.DS_Store
deleted file mode 100644
index fe88442..0000000
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/.DS_Store and /dev/null differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo
deleted file mode 100644
index 2e42e7a..0000000
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo and /dev/null differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo
index 0b02d51..1978e3a 100644
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo and b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo
index a3cb86a..920c79d 100644
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo and b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc
deleted file mode 100644
index 64d695a..0000000
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc and /dev/null differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule
deleted file mode 100644
index bb00dce..0000000
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios-simulator.swiftmodule and /dev/null differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftinterface b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftinterface
new file mode 100644
index 0000000..f1dd976
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftinterface
@@ -0,0 +1,47 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
+// swift-module-flags: -target arm64-apple-ios11.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name SigmaInteractiveSDK
+import Foundation
+@_exported import SigmaInteractiveSDK
+import Swift
+import WebKit
+import _Concurrency
+public protocol SigmaJSInterface {
+ func onReady()
+ func onShowOverlay()
+ func onHideOverlay()
+ func onForceFullScreen()
+ func onExitFullScreen()
+ func setSession(_ session: Swift.String)
+ func fullReload()
+}
+@objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor(unsafe) public class SigmaWebview : WebKit.WKWebView, WebKit.WKScriptMessageHandler, SigmaInteractiveSDK.SigmaJSInterface, WebKit.WKUIDelegate, WebKit.WKNavigationDelegate {
+ @_Concurrency.MainActor(unsafe) public init(_ interactiveLink: Swift.String)
+ @_Concurrency.MainActor(unsafe) @objc public func webView(_ webView: WebKit.WKWebView, decidePolicyFor navigationAction: WebKit.WKNavigationAction, decisionHandler: @escaping (WebKit.WKNavigationActionPolicy) -> Swift.Void)
+ @_Concurrency.MainActor(unsafe) public func setPlayerRectView()
+ @objc(setUserData:) @_Concurrency.MainActor(unsafe) public func setUserData(value: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func setUserValue(value: [Swift.String : Any])
+ @_Concurrency.MainActor(unsafe) public func sendUserValue(value: [Swift.String : Any])
+ @objc(sendID3TagInstant:) @_Concurrency.MainActor(unsafe) public func sendID3TagInstant(value: Swift.String)
+ @objc(sendID3Tag:) @_Concurrency.MainActor(unsafe) public func sendID3Tag(value: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func onShowOverlay()
+ @_Concurrency.MainActor(unsafe) public func onHideOverlay()
+ @_Concurrency.MainActor(unsafe) public func onForceFullScreen()
+ @_Concurrency.MainActor(unsafe) public func onExitFullScreen()
+ @_Concurrency.MainActor(unsafe) public func setSession(_ session: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func fullReload()
+ @_Concurrency.MainActor(unsafe) public func onChangeOverlayRects(payload: Swift.Array)
+ @_Concurrency.MainActor(unsafe) @objc public func userContentController(_ userContentController: WebKit.WKUserContentController, didReceive message: WebKit.WKScriptMessage)
+ @objc(loadWithUrl:) @_Concurrency.MainActor(unsafe) public func loadUrl(url: Swift.String)
+ @objc(setX:setY:setWidth:setHeight:setXPlayer:setYPlayer:setWidthPlayer:setHeightPlayer:) @_Concurrency.MainActor(unsafe) public func setLayout(x: Swift.Int, y: Swift.Int, width: Swift.Int, height: Swift.Int, xPlayer: Swift.Int, yPlayer: Swift.Int, widthPlayer: Swift.Int, heightPlayer: Swift.Int)
+ @objc(setViewOrientation:) @_Concurrency.MainActor(unsafe) public func setViewOrientation(orientation: Swift.String)
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public func point(inside point: CoreGraphics.CGPoint, with event: UIKit.UIEvent?) -> Swift.Bool
+ @_Concurrency.MainActor(unsafe) public func onReady()
+ @_Concurrency.MainActor(unsafe) public func sendDataOnReady()
+ @_Concurrency.MainActor(unsafe) public func setCallBack(sigmaInteractiveCallback: SigmaInteractiveSDK.SigmaJSInterface)
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public func shouldUpdateFocus(in context: UIKit.UIFocusUpdateContext) -> Swift.Bool
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public var safeAreaInsets: UIKit.UIEdgeInsets {
+ @_Concurrency.MainActor(unsafe) @objc get
+ }
+ @objc deinit
+}
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule
index 01ac658..47af645 100644
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule and b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
new file mode 100644
index 0000000..679483b
--- /dev/null
+++ b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface
@@ -0,0 +1,47 @@
+// swift-interface-format-version: 1.0
+// swift-compiler-version: Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)
+// swift-module-flags: -target x86_64-apple-ios11.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -Onone -module-name SigmaInteractiveSDK
+import Foundation
+@_exported import SigmaInteractiveSDK
+import Swift
+import WebKit
+import _Concurrency
+public protocol SigmaJSInterface {
+ func onReady()
+ func onShowOverlay()
+ func onHideOverlay()
+ func onForceFullScreen()
+ func onExitFullScreen()
+ func setSession(_ session: Swift.String)
+ func fullReload()
+}
+@objc @_hasMissingDesignatedInitializers @_Concurrency.MainActor(unsafe) public class SigmaWebview : WebKit.WKWebView, WebKit.WKScriptMessageHandler, SigmaInteractiveSDK.SigmaJSInterface, WebKit.WKUIDelegate, WebKit.WKNavigationDelegate {
+ @_Concurrency.MainActor(unsafe) public init(_ interactiveLink: Swift.String)
+ @_Concurrency.MainActor(unsafe) @objc public func webView(_ webView: WebKit.WKWebView, decidePolicyFor navigationAction: WebKit.WKNavigationAction, decisionHandler: @escaping (WebKit.WKNavigationActionPolicy) -> Swift.Void)
+ @_Concurrency.MainActor(unsafe) public func setPlayerRectView()
+ @objc(setUserData:) @_Concurrency.MainActor(unsafe) public func setUserData(value: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func setUserValue(value: [Swift.String : Any])
+ @_Concurrency.MainActor(unsafe) public func sendUserValue(value: [Swift.String : Any])
+ @objc(sendID3TagInstant:) @_Concurrency.MainActor(unsafe) public func sendID3TagInstant(value: Swift.String)
+ @objc(sendID3Tag:) @_Concurrency.MainActor(unsafe) public func sendID3Tag(value: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func onShowOverlay()
+ @_Concurrency.MainActor(unsafe) public func onHideOverlay()
+ @_Concurrency.MainActor(unsafe) public func onForceFullScreen()
+ @_Concurrency.MainActor(unsafe) public func onExitFullScreen()
+ @_Concurrency.MainActor(unsafe) public func setSession(_ session: Swift.String)
+ @_Concurrency.MainActor(unsafe) public func fullReload()
+ @_Concurrency.MainActor(unsafe) public func onChangeOverlayRects(payload: Swift.Array)
+ @_Concurrency.MainActor(unsafe) @objc public func userContentController(_ userContentController: WebKit.WKUserContentController, didReceive message: WebKit.WKScriptMessage)
+ @objc(loadWithUrl:) @_Concurrency.MainActor(unsafe) public func loadUrl(url: Swift.String)
+ @objc(setX:setY:setWidth:setHeight:setXPlayer:setYPlayer:setWidthPlayer:setHeightPlayer:) @_Concurrency.MainActor(unsafe) public func setLayout(x: Swift.Int, y: Swift.Int, width: Swift.Int, height: Swift.Int, xPlayer: Swift.Int, yPlayer: Swift.Int, widthPlayer: Swift.Int, heightPlayer: Swift.Int)
+ @objc(setViewOrientation:) @_Concurrency.MainActor(unsafe) public func setViewOrientation(orientation: Swift.String)
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public func point(inside point: CoreGraphics.CGPoint, with event: UIKit.UIEvent?) -> Swift.Bool
+ @_Concurrency.MainActor(unsafe) public func onReady()
+ @_Concurrency.MainActor(unsafe) public func sendDataOnReady()
+ @_Concurrency.MainActor(unsafe) public func setCallBack(sigmaInteractiveCallback: SigmaInteractiveSDK.SigmaJSInterface)
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public func shouldUpdateFocus(in context: UIKit.UIFocusUpdateContext) -> Swift.Bool
+ @_Concurrency.MainActor(unsafe) @objc override dynamic public var safeAreaInsets: UIKit.UIEdgeInsets {
+ @_Concurrency.MainActor(unsafe) @objc get
+ }
+ @objc deinit
+}
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule
index 61aed95..532e591 100644
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule and b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/Modules/SigmaInteractiveSDK.swiftmodule/x86_64-apple-ios-simulator.swiftmodule differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/SigmaInteractiveSDK b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/SigmaInteractiveSDK
index 600a753..c928abf 100755
Binary files a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/SigmaInteractiveSDK and b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/SigmaInteractiveSDK differ
diff --git a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/_CodeSignature/CodeResources b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/_CodeSignature/CodeResources
index 465c600..dd9fbfd 100644
--- a/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/_CodeSignature/CodeResources
+++ b/DemoSigmaInteractiveIOS/SigmaInteractiveSDK.framework/_CodeSignature/CodeResources
@@ -6,7 +6,7 @@
Headers/SigmaInteractiveSDK-Swift.h
- vctMWUpUAzXUadx1c504K8J1kak=
+ LYhE7cGTEdR2pOU5y8a5tDEN1ic=
Headers/SigmaInteractiveSDK.h
@@ -18,15 +18,19 @@
Modules/SigmaInteractiveSDK.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo
- mqkXh2MFtcetBEjfc5ZoSMXEHCo=
+ +0iIJ2U64mBl32DlqUevNo7Buio=
Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftdoc
VnTBSudEF+USe81sWRj29PAwzUA=
+ Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftinterface
+
+ nMhvSwY0BHFLz+HTlT/wlmu/sMc=
+
Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule
- SAC8HX2wqsfQR3RnpWsVZOywZjI=
+ 0ISdZKPDV1otDUk0yelvql/s1UQ=
Modules/module.modulemap
@@ -39,7 +43,7 @@
hash2
- Gpls0krC3YotRwc/0Bp+ytEPu8DPDxsm0G3LCniOrkA=
+ io0kPu+hln0Qd/NTaJJrMM5pQnWXhkSFGm0R7/REWzQ=
Headers/SigmaInteractiveSDK.h
@@ -53,7 +57,7 @@
hash2
- 8PIjL+jytGF0GrnDYwy/9+vgbK4YBtdYoaX9GIo/iw0=
+ 35IwHZ8FCglT9tHe5fw8moHguRStBHAMqRoyzPmxvLs=
Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftdoc
@@ -63,11 +67,18 @@
QEibBVioLyFlL9amnMwtMa3auO37s6DG7TzI4Si+b3o=
+ Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftinterface
+
+ hash2
+
+ qcE3fmBabDZnylDTgP9UrnBFtOo62vvhsWXn/e6O3Lg=
+
+
Modules/SigmaInteractiveSDK.swiftmodule/arm64-apple-ios.swiftmodule
hash2
- m8G/cw0s9Mr6jxNNkIjIoBeY0m5wAzdGbsr4CXQuL6E=
+ Cy1EIibt854cBOUmXdf/KGsGANPtlp4BbSSg/rNmCTI=
Modules/module.modulemap