@24i/smartapps-bigscreen-rnv-build-engine 0.17.2 → 0.17.3-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/src/__tests__/resolvers/resolveBuildFileBaseName.spec.js +80 -0
  2. package/dist/src/resolvers/index.js +3 -1
  3. package/dist/src/resolvers/resolveBuildFileBaseName.js +34 -0
  4. package/dist/src/resolvers/resolveBuildFileName.js +3 -27
  5. package/dist/src/scripts/releaseAllWithScheme.js +1 -1
  6. package/dist/src/sdks/index.js +5 -1
  7. package/dist/src/sdks/sdk-androidtv/index.js +17 -0
  8. package/dist/src/sdks/sdk-androidtv/sdkAndroidtv.js +264 -0
  9. package/dist/src/sdks/sdk-utils/sdk-installer/services/unzip.js +3 -2
  10. package/dist/src/tasks/task.rnv.build.js +3 -1
  11. package/dist/src/tasks/task.rnv.configure.js +3 -1
  12. package/dist/src/tasks/task.rnv.platform.configure.js +4 -1
  13. package/dist/templates/platforms/_shared/template.js +3 -3
  14. package/dist/templates/platforms/androidtv/project/README.md +196 -0
  15. package/dist/templates/platforms/androidtv/project/amazoniap/build.gradle +37 -0
  16. package/dist/templates/platforms/androidtv/project/amazoniap/consumer-rules.pro +0 -0
  17. package/dist/templates/platforms/androidtv/project/amazoniap/libs/in-app-purchasing-2.0.76.jar +0 -0
  18. package/dist/templates/platforms/androidtv/project/amazoniap/proguard-rules.pro +21 -0
  19. package/dist/templates/platforms/androidtv/project/amazoniap/src/main/AndroidManifest.xml +4 -0
  20. package/dist/templates/platforms/androidtv/project/amazoniap/src/main/java/com/twentyfouri/bridgetv/amazoniap/AmazonIapSevice.kt +106 -0
  21. package/dist/templates/platforms/androidtv/project/app/build.gradle +112 -0
  22. package/dist/templates/platforms/androidtv/project/app/proguard-rules.pro +32 -0
  23. package/dist/templates/platforms/androidtv/project/app/src/bigscreenAppstage/java/com/twentyfouri/tvbridge/Flavor.kt +5 -0
  24. package/dist/templates/platforms/androidtv/project/app/src/bigscreenAppstage/res/raw/configuration.json +9 -0
  25. package/dist/templates/platforms/androidtv/project/app/src/main/AndroidManifest.xml +53 -0
  26. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/FlavorBase.kt +12 -0
  27. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeFromJavaScript.kt +392 -0
  28. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeToJavaScript.kt +89 -0
  29. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/BridgeConfig.kt +16 -0
  30. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/ConfigCallback.kt +6 -0
  31. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/ConfigProvider.kt +27 -0
  32. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/Drm.kt +10 -0
  33. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/UserAgent.kt +6 -0
  34. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/BaseApplication.kt +73 -0
  35. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ActivityComponent.kt +13 -0
  36. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ActivityModule.kt +17 -0
  37. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ApplicationComponent.kt +26 -0
  38. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ApplicationModule.kt +51 -0
  39. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/PerActivity.kt +26 -0
  40. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/LocalStorage.kt +30 -0
  41. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/LoggingDrmCallback.kt +38 -0
  42. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/OverriddenHttpMediaDrmCallback.kt +134 -0
  43. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryExoPlayerCustomized.kt +84 -0
  44. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/SimpleActivityLifecycleCallback.kt +32 -0
  45. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/SourceDrmOverridden.kt +49 -0
  46. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/jump/JumpAnalytics.kt +211 -0
  47. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/sound/TouchPlayer.kt +86 -0
  48. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/client/BridgeWebView.kt +82 -0
  49. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/client/BridgeWebViewClient.kt +114 -0
  50. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/AnalyticsPlaybackInfo.kt +10 -0
  51. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/ContentModel.kt +14 -0
  52. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/DrmModel.kt +20 -0
  53. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/MediaEventType.kt +20 -0
  54. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/ContentModelParser.kt +16 -0
  55. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/DeviceInfoParser.kt +22 -0
  56. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/PlaybackInfoParser.kt +10 -0
  57. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/TrackJsonModelParser.kt +58 -0
  58. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/Mainview.kt +20 -0
  59. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/PlayerCache.kt +15 -0
  60. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/WebViewActivity.kt +306 -0
  61. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/viewmodel/WebViewModel.kt +609 -0
  62. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_focus.xml +10 -0
  63. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_normal.xml +7 -0
  64. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_pressed.xml +7 -0
  65. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_focus.xml +8 -0
  66. package/dist/templates/platforms/androidtv/project/app/src/main/res/layout/activity_web_view.xml +76 -0
  67. package/dist/templates/platforms/androidtv/project/app/src/main/res/raw/click.ogg +0 -0
  68. package/dist/templates/platforms/androidtv/project/app/src/main/res/values/styles.xml +12 -0
  69. package/dist/templates/platforms/androidtv/project/app/src/main/res/xml/network_security_config.xml +4 -0
  70. package/dist/templates/platforms/androidtv/project/build.gradle +48 -0
  71. package/dist/templates/platforms/androidtv/project/common/build.gradle +36 -0
  72. package/dist/templates/platforms/androidtv/project/common/consumer-rules.pro +0 -0
  73. package/dist/templates/platforms/androidtv/project/common/proguard-rules.pro +21 -0
  74. package/dist/templates/platforms/androidtv/project/common/src/main/AndroidManifest.xml +4 -0
  75. package/dist/templates/platforms/androidtv/project/common/src/main/java/com/twentyfouri/tvbridge/common/IapService.kt +114 -0
  76. package/dist/templates/platforms/androidtv/project/googleiap/build.gradle +38 -0
  77. package/dist/templates/platforms/androidtv/project/googleiap/consumer-rules.pro +0 -0
  78. package/dist/templates/platforms/androidtv/project/googleiap/proguard-rules.pro +21 -0
  79. package/dist/templates/platforms/androidtv/project/googleiap/src/main/AndroidManifest.xml +6 -0
  80. package/dist/templates/platforms/androidtv/project/googleiap/src/main/java/com/twentyfouri/tvbridge/googleiap/GoogleIapService.kt +29 -0
  81. package/dist/templates/platforms/androidtv/project/gradle/wrapper/gradle-wrapper.jar +0 -0
  82. package/dist/templates/platforms/androidtv/project/gradle/wrapper/gradle-wrapper.properties +6 -0
  83. package/dist/templates/platforms/androidtv/project/gradle.properties +4 -0
  84. package/dist/templates/platforms/androidtv/project/gradlew +185 -0
  85. package/dist/templates/platforms/androidtv/project/gradlew.bat +104 -0
  86. package/dist/templates/platforms/androidtv/project/proguard-rules.pro +42 -0
  87. package/dist/templates/platforms/androidtv/project/settings.gradle +4 -0
  88. package/package.json +3 -2
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const resolveBuildFileBaseName_1 = require("../../resolvers/resolveBuildFileBaseName");
4
+ const resolveGenericRnvConfig_1 = require("../../resolvers/resolveGenericRnvConfig");
5
+ const resolveBuildVersionOffset_1 = require("../../resolvers/resolveBuildVersionOffset");
6
+ const constants_1 = require("../../constants");
7
+ jest.mock('../../resolvers/resolveGenericRnvConfig');
8
+ jest.mock('../../resolvers/resolveBuildVersionOffset');
9
+ describe('resolveBuildFileBaseName', () => {
10
+ let c = {};
11
+ beforeEach(() => {
12
+ resolveGenericRnvConfig_1.getBaseConfig.mockReturnValue({
13
+ runtime: {},
14
+ buildConfig: { common: { packageVersion: '1.0.0' } },
15
+ });
16
+ });
17
+ afterEach(() => {
18
+ jest.clearAllMocks();
19
+ jest.resetAllMocks();
20
+ jest.resetModules();
21
+ });
22
+ beforeEach(() => {
23
+ c = {
24
+ runtime: { appId: 'flavour' },
25
+ buildConfig: {
26
+ common: { appNameInFileName: 'appName' },
27
+ },
28
+ };
29
+ });
30
+ it('returns proper string when there is no version offset', () => {
31
+ resolveBuildVersionOffset_1.resolveBuildVersionOffset.mockReturnValue('');
32
+ Object.values(constants_1.Platforms).forEach((platform) => {
33
+ c.platform = platform;
34
+ c.runtime.scheme = constants_1.BuildSchemes.DEBUG;
35
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.debug_flavour`);
36
+ c.runtime.scheme = constants_1.BuildSchemes.DEV;
37
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.dev_flavour`);
38
+ c.runtime.scheme = constants_1.BuildSchemes.DEV_LATEST;
39
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.dev_flavour`);
40
+ c.runtime.scheme = constants_1.BuildSchemes.RC;
41
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.rc_flavour`);
42
+ c.runtime.scheme = constants_1.BuildSchemes.RC_LATEST;
43
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.rc_flavour`);
44
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE;
45
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0_flavour`);
46
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE_LATEST;
47
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.release_flavour`);
48
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE_DIST;
49
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0_flavour`);
50
+ });
51
+ });
52
+ it('returns proper string when there is version offset', () => {
53
+ resolveBuildVersionOffset_1.resolveBuildVersionOffset.mockReturnValue('1');
54
+ Object.values(constants_1.Platforms).forEach((platform) => {
55
+ c.platform = platform;
56
+ c.runtime.scheme = constants_1.BuildSchemes.DEBUG;
57
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.debug-1_flavour`);
58
+ c.runtime.scheme = constants_1.BuildSchemes.DEV;
59
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.dev-1_flavour`);
60
+ c.runtime.scheme = constants_1.BuildSchemes.DEV_LATEST;
61
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.dev_flavour`);
62
+ c.runtime.scheme = constants_1.BuildSchemes.RC;
63
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0.rc-1_flavour`);
64
+ c.runtime.scheme = constants_1.BuildSchemes.RC_LATEST;
65
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.rc_flavour`);
66
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE;
67
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0-1_flavour`);
68
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE_LATEST;
69
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_latest.release_flavour`);
70
+ c.runtime.scheme = constants_1.BuildSchemes.RELEASE_DIST;
71
+ expect((0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c)).toBe(`appName_${platform}_v1.0.0-1_flavour`);
72
+ });
73
+ });
74
+ it('throws an error when c.buildConfig.common.appNameInFileName is not present', () => {
75
+ c.buildConfig.common.appNameInFileName = '';
76
+ expect(() => {
77
+ (0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c);
78
+ }).toThrowError(new Error('Missing value for "c.buildConfig.common.appNameInFileName"!'));
79
+ });
80
+ });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveZippedPlatformBuildsRelativeFilePath = exports.resolvePackageVersions = exports.resolveBuildFileExtension = exports.resolveUsedFlavours = exports.resolveSupportedPlatforms = exports.getBaseConfig = exports.resolveBuildFileName = exports.resolveHbbtvDeployConfig = exports.resolveHbbtvDeployUrl = exports.resolveHbbtvRemoteBuildDirRelativePath = exports.resolveDeployLocations = exports.resolveBuildVersionOffset = exports.resolveBuildVersion = exports.resolveBaseUrl = void 0;
3
+ exports.resolveZippedPlatformBuildsRelativeFilePath = exports.resolvePackageVersions = exports.resolveBuildFileExtension = exports.resolveUsedFlavours = exports.resolveSupportedPlatforms = exports.getBaseConfig = exports.resolveBuildFileName = exports.resolveBuildFileBaseName = exports.resolveHbbtvDeployConfig = exports.resolveHbbtvDeployUrl = exports.resolveHbbtvRemoteBuildDirRelativePath = exports.resolveDeployLocations = exports.resolveBuildVersionOffset = exports.resolveBuildVersion = exports.resolveBaseUrl = void 0;
4
4
  var resolveBaseUrl_1 = require("./resolveBaseUrl");
5
5
  Object.defineProperty(exports, "resolveBaseUrl", { enumerable: true, get: function () { return resolveBaseUrl_1.resolveBaseUrl; } });
6
6
  var resolveBuildVersion_1 = require("./resolveBuildVersion");
@@ -15,6 +15,8 @@ var resolveHbbtvDeployUrl_1 = require("./resolveHbbtvDeployUrl");
15
15
  Object.defineProperty(exports, "resolveHbbtvDeployUrl", { enumerable: true, get: function () { return resolveHbbtvDeployUrl_1.resolveHbbtvDeployUrl; } });
16
16
  var resolveHbbtvDeployConfig_1 = require("./resolveHbbtvDeployConfig");
17
17
  Object.defineProperty(exports, "resolveHbbtvDeployConfig", { enumerable: true, get: function () { return resolveHbbtvDeployConfig_1.resolveHbbtvDeployConfig; } });
18
+ var resolveBuildFileBaseName_1 = require("./resolveBuildFileBaseName");
19
+ Object.defineProperty(exports, "resolveBuildFileBaseName", { enumerable: true, get: function () { return resolveBuildFileBaseName_1.resolveBuildFileBaseName; } });
18
20
  var resolveBuildFileName_1 = require("./resolveBuildFileName");
19
21
  Object.defineProperty(exports, "resolveBuildFileName", { enumerable: true, get: function () { return resolveBuildFileName_1.resolveBuildFileName; } });
20
22
  var resolveGenericRnvConfig_1 = require("./resolveGenericRnvConfig");
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveBuildFileBaseName = void 0;
4
+ const resolveBuildVersion_1 = require("./resolveBuildVersion");
5
+ const constants_1 = require("../constants");
6
+ const getBuildVersionForFileName = (c) => {
7
+ const { platform, runtime } = c;
8
+ const { scheme, appId } = runtime;
9
+ switch (c.runtime.scheme) {
10
+ case constants_1.BuildSchemes.DEV_LATEST:
11
+ return 'latest.dev';
12
+ case constants_1.BuildSchemes.RC_LATEST:
13
+ return 'latest.rc';
14
+ case constants_1.BuildSchemes.RELEASE_LATEST:
15
+ return 'latest.release';
16
+ default:
17
+ return (0, resolveBuildVersion_1.resolveBuildVersion)({
18
+ platform,
19
+ scheme,
20
+ flavour: appId,
21
+ });
22
+ }
23
+ };
24
+ const resolveBuildFileBaseName = (c) => {
25
+ const platformName = c.platform;
26
+ const { appNameInFileName } = c.buildConfig.common;
27
+ if (!appNameInFileName) {
28
+ throw new Error('Missing value for "c.buildConfig.common.appNameInFileName"!');
29
+ }
30
+ const appConfigId = c.runtime.appId;
31
+ const buildVersion = getBuildVersionForFileName(c);
32
+ return `${appNameInFileName}_${platformName}_${buildVersion}_${appConfigId}`;
33
+ };
34
+ exports.resolveBuildFileBaseName = resolveBuildFileBaseName;
@@ -1,36 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveBuildFileName = void 0;
4
- const resolveBuildVersion_1 = require("./resolveBuildVersion");
5
- const constants_1 = require("../constants");
4
+ const resolveBuildFileBaseName_1 = require("./resolveBuildFileBaseName");
6
5
  const resolveBuildFileExtension_1 = require("./resolveBuildFileExtension");
7
- const getBuildVersionForFileName = (c) => {
8
- const { platform, runtime } = c;
9
- const { scheme, appId } = runtime;
10
- switch (c.runtime.scheme) {
11
- case constants_1.BuildSchemes.DEV_LATEST:
12
- return 'latest.dev';
13
- case constants_1.BuildSchemes.RC_LATEST:
14
- return 'latest.rc';
15
- case constants_1.BuildSchemes.RELEASE_LATEST:
16
- return 'latest.release';
17
- default:
18
- return (0, resolveBuildVersion_1.resolveBuildVersion)({
19
- platform,
20
- scheme,
21
- flavour: appId,
22
- });
23
- }
24
- };
25
6
  const resolveBuildFileName = (c) => {
26
7
  const platformName = c.platform;
27
- const { appNameInFileName } = c.buildConfig.common;
28
- if (!appNameInFileName) {
29
- throw new Error('Missing value for "c.buildConfig.common.appNameInFileName"!');
30
- }
31
- const appConfigId = c.runtime.appId;
32
- const buildVersion = getBuildVersionForFileName(c);
8
+ const baseName = (0, resolveBuildFileBaseName_1.resolveBuildFileBaseName)(c);
33
9
  const extension = (0, resolveBuildFileExtension_1.resolveBuildFileExtension)(platformName);
34
- return `${appNameInFileName}_${platformName}_${buildVersion}_${appConfigId}.${extension}`;
10
+ return `${baseName}.${extension}`;
35
11
  };
36
12
  exports.resolveBuildFileName = resolveBuildFileName;
@@ -76,4 +76,4 @@ const startTimestamp = Date.now();
76
76
  releaseAllWithScheme();
77
77
  const msPerSecond = 1000;
78
78
  const scriptTotalTimeInSeconds = Math.ceil((Date.now() - startTimestamp) / msPerSecond);
79
- console.log(`buildAllWithScheme: done in ${scriptTotalTimeInSeconds} second(s)!`);
79
+ console.log(`releaseAllWithScheme: done in ${scriptTotalTimeInSeconds} second(s)!`);
@@ -23,8 +23,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.handlePlatformSdk = exports.SDKXbox = exports.SDKWebpack = exports.SDKTizen = exports.SDKWebos = void 0;
26
+ exports.handlePlatformSdk = exports.SDKXbox = exports.SDKWebpack = exports.SDKTizen = exports.SDKWebos = exports.SDKAndroidtv = void 0;
27
27
  const constants_1 = require("../constants");
28
+ const SDKAndroidtv = __importStar(require("./sdk-androidtv"));
29
+ exports.SDKAndroidtv = SDKAndroidtv;
28
30
  const SDKWebos = __importStar(require("./sdk-webos"));
29
31
  exports.SDKWebos = SDKWebos;
30
32
  const SDKTizen = __importStar(require("./sdk-tizen"));
@@ -35,6 +37,8 @@ const SDKXbox = __importStar(require("./sdk-xbox"));
35
37
  exports.SDKXbox = SDKXbox;
36
38
  const handlePlatformSdk = async (c) => {
37
39
  switch (c.platform) {
40
+ case constants_1.Platforms.ANDROIDTV:
41
+ return SDKAndroidtv.handleAndroidTVSdk(c);
38
42
  case constants_1.Platforms.TIZEN:
39
43
  return SDKTizen.handleTizenSdk(c);
40
44
  case constants_1.Platforms.WEBOS:
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./sdkAndroidtv"), exports);
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.handleAndroidTVSdk = exports.configureAndroidTVProject = exports.buildAndroidTVProject = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const os = __importStar(require("os"));
30
+ const semver = __importStar(require("semver"));
31
+ const child_process_1 = require("child_process");
32
+ const rnv_1 = require("rnv");
33
+ const sdk_webpack_1 = require("@rnv/sdk-webpack");
34
+ const sdk_webpack_2 = require("../sdk-webpack");
35
+ const sdk_utils_1 = require("../sdk-utils");
36
+ const services_1 = require("../sdk-utils/sdk-installer/services");
37
+ const resolvers_1 = require("../../resolvers");
38
+ const constants_1 = require("../../constants");
39
+ const flavourName = 'bigscreenAppstage';
40
+ const capitalizeFirstLetter = (str) => {
41
+ return str.charAt(0).toUpperCase() + str.slice(1);
42
+ };
43
+ const buildAndroidTVProject = async (c) => {
44
+ rnv_1.Logger.logTask('buildAndroidTVProject');
45
+ await (0, sdk_webpack_2.buildCoreWebpackProject)(c);
46
+ const buildType = c.runtime.scheme === constants_1.BuildSchemes.DEBUG
47
+ ? 'debug' : 'release';
48
+ if (!c.program.hosted) {
49
+ const projectDir = rnv_1.Common.getPlatformProjectDir(c);
50
+ const taskBuildType = buildType === 'debug' ? 'Debug' : 'Release';
51
+ const projectParentDir = path.join(projectDir, '..');
52
+ const outputDir = path.join(projectParentDir, 'output');
53
+ const tmpOutputDir = path.join(projectParentDir, 'tmpOutput');
54
+ const apkFileName = `app-${flavourName}-${buildType}.apk`;
55
+ const apkFilePath = path.join(projectDir, `app/build/outputs/apk/${flavourName}/${buildType}/${apkFileName}`);
56
+ const aabFileName = `app-${flavourName}-${buildType}.aab`;
57
+ const aabFilePath = path.join(projectDir, `app/build/outputs/bundle/${flavourName}${taskBuildType}/${aabFileName}`);
58
+ const gradlew = './gradlew';
59
+ const taskFlavourName = capitalizeFirstLetter(flavourName);
60
+ const taskAssembleName = `assemble${taskFlavourName}${taskBuildType}`;
61
+ const taskBundleName = `bundle${taskFlavourName}${taskBuildType}`;
62
+ const cmd1 = `cd ${projectDir} && ${gradlew} ${taskAssembleName} --stacktrace --debug`;
63
+ const cmd2 = `cd ${projectDir} && ${gradlew} ${taskBundleName} --stacktrace --debug`;
64
+ console.log(`Running command: ${cmd1}`);
65
+ (0, child_process_1.execSync)(cmd1);
66
+ console.log(`Running command: ${cmd2}`);
67
+ (0, child_process_1.execSync)(cmd2);
68
+ fs.rmSync(tmpOutputDir, { recursive: true, force: true });
69
+ fs.mkdirSync(tmpOutputDir);
70
+ if (!fs.existsSync(outputDir)) {
71
+ fs.mkdirSync(outputDir);
72
+ }
73
+ const newApkFilePath = path.join(tmpOutputDir, `${(0, resolvers_1.resolveBuildFileBaseName)(c)}.apk`);
74
+ const newAabFilePath = path.join(tmpOutputDir, `${(0, resolvers_1.resolveBuildFileBaseName)(c)}.aab`);
75
+ fs.copyFileSync(apkFilePath, newApkFilePath);
76
+ fs.copyFileSync(aabFilePath, newAabFilePath);
77
+ const zipFileName = `${(0, resolvers_1.resolveBuildFileBaseName)(c)}.zip`;
78
+ (0, child_process_1.execSync)(`zip -r ${outputDir}/${zipFileName} *`, { cwd: `${tmpOutputDir}` });
79
+ fs.rmSync(tmpOutputDir, { recursive: true, force: true });
80
+ rnv_1.Logger.logSuccess(`Your .zip with APK and AAB packages is located in ${rnv_1.Logger.chalk().cyan(outputDir)}.`);
81
+ }
82
+ };
83
+ exports.buildAndroidTVProject = buildAndroidTVProject;
84
+ const configureSigning = (c) => {
85
+ rnv_1.Logger.logTask('configureSigning');
86
+ const buildGradleFileName = 'build.gradle';
87
+ const buildGradleFilePath = path.join(rnv_1.Common.getPlatformProjectDir(c), 'app', buildGradleFileName);
88
+ if (c.runtime.scheme === constants_1.BuildSchemes.DEBUG) {
89
+ const injects = [{
90
+ pattern: '{{SIGNING_CONFIG_REF}}',
91
+ override: '',
92
+ }];
93
+ rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
94
+ return;
95
+ }
96
+ const { getConfigProp } = rnv_1.Common;
97
+ const storeFile = process.env.ANDROIDTV_STORE_FILE ?? getConfigProp(c, c.platform, 'storeFile');
98
+ const keyAlias = process.env.ANDROIDTV_KEY_ALIAS ?? getConfigProp(c, c.platform, 'keyAlias');
99
+ const storePassword = process.env.ANDROIDTV_STORE_PASSWORD ?? getConfigProp(c, c.platform, 'storePassword');
100
+ const keyPassword = process.env.ANDROIDTV_KEY_PASSWORD ?? getConfigProp(c, c.platform, 'keyPassword');
101
+ const srcStoreFilePath = path.join(process.cwd(), storeFile);
102
+ const destStoreFilePath = path.join(rnv_1.Common.getPlatformProjectDir(c), storeFile);
103
+ const destStoreFileDir = path.parse(destStoreFilePath).dir;
104
+ if (!fs.existsSync(destStoreFileDir)) {
105
+ fs.mkdirSync(destStoreFileDir, { recursive: true });
106
+ }
107
+ fs.copyFileSync(srcStoreFilePath, destStoreFilePath);
108
+ const injects = [{
109
+ pattern: '{{STORE_FILE}}',
110
+ override: destStoreFilePath,
111
+ }, {
112
+ pattern: '{{KEY_ALIAS}}',
113
+ override: keyAlias,
114
+ }, {
115
+ pattern: '{{STORE_PASSWORD}}',
116
+ override: storePassword,
117
+ }, {
118
+ pattern: '{{KEY_PASSWORD}}',
119
+ override: keyPassword,
120
+ }, {
121
+ pattern: '{{SIGNING_CONFIG_REF}}',
122
+ override: `signingConfig signingConfigs.${flavourName}`,
123
+ }];
124
+ rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
125
+ };
126
+ const configureProject = (c) => {
127
+ rnv_1.Logger.logTask('configureProject');
128
+ const buildGradleFileName = 'build.gradle';
129
+ const buildGradleFilePath = path.join(rnv_1.Common.getPlatformProjectDir(c), 'app', buildGradleFileName);
130
+ const version = semver.coerce(rnv_1.Common.getAppVersion(c, c.platform));
131
+ const semVerObj = semver.parse(version);
132
+ if (!semVerObj) {
133
+ throw new Error(`Failed to parse Application version: ${version}`);
134
+ }
135
+ const major = `${semVerObj.major}`.padStart(2, '0');
136
+ const minor = `${semVerObj.minor}`.padStart(2, '0');
137
+ const patch = `${semVerObj.patch}`.padStart(2, '0');
138
+ const versionCode = parseInt(`${major}${minor}${patch}00`, 10);
139
+ const appId = rnv_1.Common.getConfigProp(c, c.platform, 'id', '');
140
+ const minSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'minSdkVersion', 21);
141
+ const targetSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'targetSdkVersion', 31);
142
+ const compileSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'compileSdkVersion', 31);
143
+ const injects = [{
144
+ pattern: '{{MIN_SDK_VERSION}}',
145
+ override: minSdkVersion,
146
+ }, {
147
+ pattern: '{{TARGET_SDK_VERSION}}',
148
+ override: targetSdkVersion,
149
+ }, {
150
+ pattern: '{{COMPILE_SDK_VERSION}}',
151
+ override: compileSdkVersion,
152
+ }, {
153
+ pattern: '{{APP_VERSION_CODE}}',
154
+ override: versionCode,
155
+ }, {
156
+ pattern: '{{APP_VERSION_NAME}}',
157
+ override: version,
158
+ }, {
159
+ pattern: '{{APP_ID}}',
160
+ override: appId,
161
+ }];
162
+ rnv_1.Common.addSystemInjects(c, injects);
163
+ rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
164
+ };
165
+ const getHostedAppEntryUrl = (c) => {
166
+ const { platform, runtime } = c;
167
+ const baseUrl = (0, resolvers_1.resolveBaseUrl)({
168
+ platform,
169
+ scheme: runtime.scheme || '',
170
+ flavour: runtime.appId,
171
+ });
172
+ return `${baseUrl}/public/index.html`;
173
+ };
174
+ const configureEntryUrl = (c) => {
175
+ rnv_1.Logger.logTask('configureEntryUrl');
176
+ const entryUrl = getHostedAppEntryUrl(c);
177
+ const configFileName = 'configuration.json';
178
+ const injects = [{
179
+ pattern: '{{APP_URL}}',
180
+ override: entryUrl,
181
+ }];
182
+ const file = path.join(rnv_1.Common.getPlatformProjectDir(c), 'app/src', flavourName, 'res/raw', configFileName);
183
+ rnv_1.FileUtils.writeCleanFile(file, file, injects, null, c);
184
+ };
185
+ const configureAndroidTVProject = async (c) => {
186
+ rnv_1.Logger.logTask('configureAndroidTVProject');
187
+ c.runtime.platformBuildsProjectPath = rnv_1.Common.getPlatformProjectDir(c);
188
+ const platform = constants_1.Platforms.ANDROIDTV;
189
+ await rnv_1.ProjectManager.copyAssetsFolder(c, platform, `app/src/${flavourName}/res`);
190
+ await (0, sdk_webpack_1.configureCoreWebProject)(c);
191
+ await configureAndroidProperties(c);
192
+ configureProject(c);
193
+ configureEntryUrl(c);
194
+ configureSigning(c);
195
+ const gradlew = path.join(rnv_1.Common.getPlatformProjectDir(c), 'gradlew');
196
+ fs.chmodSync(gradlew, '755');
197
+ await rnv_1.ProjectManager.copyBuildsFolder(c, platform);
198
+ };
199
+ exports.configureAndroidTVProject = configureAndroidTVProject;
200
+ const configureAndroidProperties = async (c) => {
201
+ rnv_1.Logger.logTask('configureAndroidProperties');
202
+ let sdkDir = c.buildConfig?.sdks?.ANDROID_SDK || '';
203
+ if (rnv_1.Utils.isSystemWin) {
204
+ sdkDir = sdkDir.replace(/\\/g, '/');
205
+ }
206
+ const localPropertiesFilePath = path.join(rnv_1.Common.getPlatformProjectDir(c), 'local.properties');
207
+ const fileContent = `## Generated by ReNative (https://renative.org)
208
+ # from @24i/smartapps-bigscreen-rnv-build-engine package
209
+ sdk.dir=${sdkDir}`;
210
+ fs.writeFileSync(localPropertiesFilePath, fileContent);
211
+ return true;
212
+ };
213
+ const getSdkInstallerUrl = () => {
214
+ const folderUrl = 'https://dl.google.com/android/repository';
215
+ switch (os.platform()) {
216
+ case 'darwin':
217
+ return `${folderUrl}/commandlinetools-mac-8512546_latest.zip`;
218
+ case 'linux':
219
+ return `${folderUrl}/commandlinetools-linux-8512546_latest.zip`;
220
+ default:
221
+ return '';
222
+ }
223
+ };
224
+ const handleAndroidTVSdk = async (c) => {
225
+ rnv_1.Logger.logTask('handleAndroidTVSdk');
226
+ const { ANDROID_SDK_INSTALLER_URL = getSdkInstallerUrl() } = process.env;
227
+ const { ANDROID_SDK } = c.buildConfig.sdks || {};
228
+ const installPath = `${os.homedir()}/Android`;
229
+ const rnvSdkKey = 'ANDROID_SDK';
230
+ const sdkName = 'android';
231
+ const sdksToInstall = '"build-tools;30.0.2" "emulator" "patcher;v4" "platform-tools" "platforms;android-30"';
232
+ rnv_1.Logger.logInfo(`Check ${sdkName} SDK at ${ANDROID_SDK}`);
233
+ const isInstalledSDK = ANDROID_SDK ? fs.existsSync(ANDROID_SDK) : false;
234
+ if (!isInstalledSDK) {
235
+ if (fs.existsSync(installPath)) {
236
+ await (0, sdk_utils_1.registerSdkPath)(c, rnvSdkKey, installPath);
237
+ rnv_1.Logger.logInfo(`Used ${sdkName} SDK at ${c.buildConfig?.sdks?.ANDROID_SDK}`);
238
+ }
239
+ else {
240
+ const parsedZipPath = path.parse(ANDROID_SDK_INSTALLER_URL);
241
+ const downloadedFilePath = `${os.homedir()}/${parsedZipPath.base}`;
242
+ const unzippedDirPath = `${os.homedir()}/${parsedZipPath.name}`;
243
+ rnv_1.Logger.logInfo(`Downloading ${sdkName} SDK...`);
244
+ rnv_1.Logger.logDebug(`Downloading ${sdkName} SDK to ${downloadedFilePath} from ${ANDROID_SDK_INSTALLER_URL}`);
245
+ await (0, services_1.download)(ANDROID_SDK_INSTALLER_URL, downloadedFilePath);
246
+ rnv_1.Logger.logInfo(`Unpacking...`);
247
+ rnv_1.Logger.logDebug(`Unpacking from ${downloadedFilePath} to ${unzippedDirPath}`);
248
+ (0, services_1.unzip)(downloadedFilePath, unzippedDirPath);
249
+ fs.mkdirSync(`${installPath}/cmdline-tools/latest`, { recursive: true });
250
+ (0, child_process_1.execSync)(`cp -r ${unzippedDirPath}/cmdline-tools/. ${installPath}/cmdline-tools/latest`);
251
+ rnv_1.Logger.logInfo(`Installing...`);
252
+ rnv_1.Logger.logDebug(`Accepting licenses`);
253
+ (0, child_process_1.execSync)(`yes | ${installPath}/cmdline-tools/latest/bin/sdkmanager --licenses`);
254
+ rnv_1.Logger.logDebug(`Installing SDKs ${sdksToInstall}`);
255
+ (0, child_process_1.execSync)(`${installPath}/cmdline-tools/latest/bin/sdkmanager ${sdksToInstall}`);
256
+ rnv_1.Logger.logSuccess(`SDK successfully installed at: ${installPath}`);
257
+ await (0, sdk_utils_1.registerSdkPath)(c, rnvSdkKey, installPath);
258
+ }
259
+ }
260
+ else {
261
+ rnv_1.Logger.logInfo(`Used ${sdkName} SDK at ${c.buildConfig?.sdks?.ANDROID_SDK}`);
262
+ }
263
+ };
264
+ exports.handleAndroidTVSdk = handleAndroidTVSdk;
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.unzip = void 0;
4
4
  const child_process_1 = require("child_process");
5
- const unzip = (filePath) => {
5
+ const unzip = (filePath, outputDirPath) => {
6
6
  const spawnOptions = { maxBuffer: 5242880 };
7
- const unzipProcess = (0, child_process_1.spawnSync)('unzip', ['-n', filePath], spawnOptions);
7
+ const outputDirAttr = outputDirPath ? ['-d', outputDirPath] : [];
8
+ const unzipProcess = (0, child_process_1.spawnSync)('unzip', ['-n', filePath, ...outputDirAttr], spawnOptions);
8
9
  if (unzipProcess.stderr.length) {
9
10
  throw new Error(unzipProcess.stderr.toString());
10
11
  }
@@ -62,7 +62,6 @@ const buildFn = async (c, parentTask, originTask) => {
62
62
  await (0, sdks_1.handlePlatformSdk)(c);
63
63
  await rnv_1.TaskManager.executeOrSkipTask(c, TASK_PACKAGE, TASK_BUILD, originTask);
64
64
  switch (platform) {
65
- case constants_1.Platforms.ANDROIDTV:
66
65
  case constants_1.Platforms.ENTONE:
67
66
  case constants_1.Platforms.HBBTV:
68
67
  case constants_1.Platforms.KREATV:
@@ -83,6 +82,9 @@ const buildFn = async (c, parentTask, originTask) => {
83
82
  await sdks_1.SDKWebos.buildWebOSProject(c);
84
83
  renameOutput(c);
85
84
  break;
85
+ case constants_1.Platforms.ANDROIDTV:
86
+ await sdks_1.SDKAndroidtv.buildAndroidTVProject(c);
87
+ break;
86
88
  default:
87
89
  rnv_1.PlatformManager.logErrorPlatform(c);
88
90
  }
@@ -14,7 +14,6 @@ const configureFn = async (c, parentTask, originTask) => {
14
14
  if (c.program.only && !!parentTask)
15
15
  return;
16
16
  switch (c.platform) {
17
- case constants_1.Platforms.ANDROIDTV:
18
17
  case constants_1.Platforms.ENTONE:
19
18
  case constants_1.Platforms.HBBTV:
20
19
  case constants_1.Platforms.KREATV:
@@ -30,6 +29,9 @@ const configureFn = async (c, parentTask, originTask) => {
30
29
  case constants_1.Platforms.WEBOS:
31
30
  await sdks_1.SDKWebos.configureWebOSProject(c);
32
31
  break;
32
+ case constants_1.Platforms.ANDROIDTV:
33
+ await sdks_1.SDKAndroidtv.configureAndroidTVProject(c);
34
+ break;
33
35
  default:
34
36
  rnv_1.PlatformManager.logErrorPlatform(c);
35
37
  }
@@ -4,6 +4,8 @@ exports.customRnvPlatformConfigureTask = void 0;
4
4
  const rnv_1 = require("rnv");
5
5
  const schemeParser_1 = require("rnv/dist/core/configManager/schemeParser");
6
6
  const packageParser_1 = require("rnv/dist/core/configManager/packageParser");
7
+ const replaceRelevantStringsInConfig_1 = require("../utils/replaceRelevantStringsInConfig");
8
+ const sdks_1 = require("../sdks");
7
9
  const constants_1 = require("../constants");
8
10
  const { TASK_PLATFORM_CONFIGURE, TASK_PROJECT_CONFIGURE, TASK_INSTALL, PARAMS } = rnv_1.Constants;
9
11
  const taskRnvPlatformConfigure = async (c, parentTask, originTask) => {
@@ -13,11 +15,12 @@ const taskRnvPlatformConfigure = async (c, parentTask, originTask) => {
13
15
  await rnv_1.PlatformManager.isPlatformSupported(c);
14
16
  await (0, schemeParser_1.isBuildSchemeSupported)(c);
15
17
  if (platform === constants_1.Platforms.ANDROIDTV) {
16
- rnv_1.Logger.logWarning('We skip check SDK (temporary solution)');
18
+ await (0, sdks_1.handlePlatformSdk)(c);
17
19
  }
18
20
  else {
19
21
  await rnv_1.SDKManager.Installer.checkSdk(c);
20
22
  }
23
+ (0, replaceRelevantStringsInConfig_1.replaceRelevantStringsInConfig)(c);
21
24
  await rnv_1.RuntimeManager.configureRuntimeDefaults(c);
22
25
  if (c.program.only && !!parentTask)
23
26
  return;
@@ -40,9 +40,9 @@ const htmlTemp = (options) => {
40
40
  if (platform === 'tizen') {
41
41
  tizenScripts = '<script type="text/javascript" src="$WEBAPIS/webapis/webapis.js"></script>';
42
42
  }
43
- let webtvScripts = '';
43
+ let faviconTag = '<link id="favicon" rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">';
44
44
  if (platform === 'webtv') {
45
- webtvScripts = `
45
+ faviconTag = `
46
46
  <script>
47
47
  window.onload = function(err) {
48
48
  var faviconElement = document.getElementById('favicon');
@@ -71,7 +71,7 @@ ${htmlTag}
71
71
  ${isDebug ? errScript : ''}
72
72
  ${tizenScripts}
73
73
  ${xboxScripts}
74
- ${webtvScripts}
74
+ ${faviconTag}
75
75
  ${headAppend}
76
76
  </head>
77
77
  <body>