diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index fcad46b946..cc08b41de5 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -140,6 +140,7 @@ $injector.require("previewAppLiveSyncService", "./services/livesync/playground/p $injector.require("previewAppLogProvider", "./services/livesync/playground/preview-app-log-provider"); $injector.require("previewAppPluginsService", "./services/livesync/playground/preview-app-plugins-service"); $injector.require("previewSdkService", "./services/livesync/playground/preview-sdk-service"); +$injector.require("previewSchemaService", "./services/livesync/playground/preview-schema-service"); $injector.requirePublicClass("previewDevicesService", "./services/livesync/playground/devices/preview-devices-service"); $injector.requirePublic("previewQrCodeService", "./services/livesync/playground/preview-qr-code-service"); $injector.requirePublic("sysInfo", "./sys-info"); diff --git a/lib/definitions/preview-app-livesync.d.ts b/lib/definitions/preview-app-livesync.d.ts index 4eef7d8cc7..123ae2e721 100644 --- a/lib/definitions/preview-app-livesync.d.ts +++ b/lib/definitions/preview-app-livesync.d.ts @@ -22,7 +22,7 @@ declare global { interface IPreviewSdkService extends EventEmitter { getQrCodeUrl(options: IGetQrCodeUrlOptions): string; - initialize(getInitialFiles: (device: Device) => Promise): void; + initialize(projectDir: string, getInitialFiles: (device: Device) => Promise): void; applyChanges(filesPayload: FilesPayload): Promise; stop(): void; } @@ -45,7 +45,7 @@ declare global { printLiveSyncQrCode(options: IPrintLiveSyncOptions): Promise; } - interface IPlaygroundAppQrCodeOptions { + interface IPlaygroundAppQrCodeOptions extends IProjectDir { platform?: string; } @@ -64,4 +64,20 @@ declare global { getDevicesForPlatform(platform: string): Device[]; getPluginsUsageWarnings(data: IPreviewAppLiveSyncData, device: Device): string[]; } + + interface IPreviewSchemaService { + getSchemaData(projectDir: string): IPreviewSchemaData; + } + + interface IPreviewSchemaData { + name: string; + scannerAppId: string; + scannerAppStoreId: string; + previewAppId: string; + previewAppStoreId: string; + msvKey: string; + publishKey: string; + subscribeKey: string; + default?: boolean; + } } \ No newline at end of file diff --git a/lib/services/livesync/playground/preview-app-constants.ts b/lib/services/livesync/playground/preview-app-constants.ts index fd8ac000e6..084a9db3b3 100644 --- a/lib/services/livesync/playground/preview-app-constants.ts +++ b/lib/services/livesync/playground/preview-app-constants.ts @@ -8,11 +8,6 @@ export class PubnubKeys { public static SUBSCRIBE_KEY = "sub-c-3dad1ebe-aaa3-11e8-8027-363023237e0b"; } -export class PlaygroundStoreUrls { - public static GOOGLE_PLAY_URL = "https://play.google.com/store/apps/details?id=org.nativescript.play"; - public static APP_STORE_URL = "https://itunes.apple.com/us/app/nativescript-playground/id1263543946?mt=8&ls=1"; -} - export class PluginComparisonMessages { public static PLUGIN_NOT_INCLUDED_IN_PREVIEW_APP = "Plugin %s is not included in preview app on device %s and will not work."; public static LOCAL_PLUGIN_WITH_DIFFERENCE_IN_MAJOR_VERSION = "Local plugin %s differs in major version from plugin in preview app. The local plugin has version %s and the plugin in preview app has version %s. Some features might not work as expected."; diff --git a/lib/services/livesync/playground/preview-app-livesync-service.ts b/lib/services/livesync/playground/preview-app-livesync-service.ts index b1d2d6537d..ad59828b55 100644 --- a/lib/services/livesync/playground/preview-app-livesync-service.ts +++ b/lib/services/livesync/playground/preview-app-livesync-service.ts @@ -28,7 +28,7 @@ export class PreviewAppLiveSyncService extends EventEmitter implements IPreviewA @performanceLog() public async initialize(data: IPreviewAppLiveSyncData): Promise { - await this.$previewSdkService.initialize(async (device: Device) => { + await this.$previewSdkService.initialize(data.projectDir, async (device: Device) => { try { if (!device) { this.$errors.failWithoutHelp("Sending initial preview files without a specified device is not supported."); diff --git a/lib/services/livesync/playground/preview-qr-code-service.ts b/lib/services/livesync/playground/preview-qr-code-service.ts index 5d5048b8a3..4d369c22e8 100644 --- a/lib/services/livesync/playground/preview-qr-code-service.ts +++ b/lib/services/livesync/playground/preview-qr-code-service.ts @@ -1,6 +1,5 @@ import * as util from "util"; import { EOL } from "os"; -import { PlaygroundStoreUrls } from "./preview-app-constants"; import { exported } from "../../../common/decorators"; export class PreviewQrCodeService implements IPreviewQrCodeService { @@ -10,20 +9,22 @@ export class PreviewQrCodeService implements IPreviewQrCodeService { private $logger: ILogger, private $mobileHelper: Mobile.IMobileHelper, private $previewSdkService: IPreviewSdkService, + private $previewSchemaService: IPreviewSchemaService, private $qrCodeTerminalService: IQrCodeTerminalService, private $qr: IQrCodeGenerator ) { } @exported("previewQrCodeService") public async getPlaygroundAppQrCode(options?: IPlaygroundAppQrCodeOptions): Promise> { + const { projectDir } = options; const result = Object.create(null); if (!options || !options.platform || this.$mobileHelper.isAndroidPlatform(options.platform)) { - result.android = await this.getLiveSyncQrCode(PlaygroundStoreUrls.GOOGLE_PLAY_URL); + result.android = await this.getLiveSyncQrCode(this.getGooglePlayUrl(projectDir)); } if (!options || !options.platform || this.$mobileHelper.isiOSPlatform(options.platform)) { - result.ios = await this.getLiveSyncQrCode(PlaygroundStoreUrls.APP_STORE_URL); + result.ios = await this.getLiveSyncQrCode(this.getAppStoreUrl(projectDir)); } return result; @@ -56,8 +57,8 @@ export class PreviewQrCodeService implements IPreviewQrCodeService { this.$logger.printMarkdown(`# Use \`NativeScript Playground app\` and scan the \`QR code\` above to preview the application on your device.`); this.$logger.printMarkdown(` To scan the QR code and deploy your app on a device, you need to have the \`NativeScript Playground app\`: - App Store (iOS): ${PlaygroundStoreUrls.APP_STORE_URL} - Google Play (Android): ${PlaygroundStoreUrls.GOOGLE_PLAY_URL}`); + App Store (iOS): ${this.getAppStoreUrl(options.projectDir)} + Google Play (Android): ${this.getGooglePlayUrl(options.projectDir)}`); } } @@ -73,5 +74,15 @@ To scan the QR code and deploy your app on a device, you need to have the \`Nati return url; } + + private getGooglePlayUrl(projectDir: string): string { + const schema = this.$previewSchemaService.getSchemaData(projectDir); + return `https://play.google.com/store/apps/details?id=${schema.scannerAppId}`; + } + + private getAppStoreUrl(projectDir: string): string { + const schema = this.$previewSchemaService.getSchemaData(projectDir); + return `https://itunes.apple.com/us/app/nativescript-playground/id${schema.scannerAppStoreId}?mt=8&ls=1`; + } } $injector.register("previewQrCodeService", PreviewQrCodeService); diff --git a/lib/services/livesync/playground/preview-schema-service.ts b/lib/services/livesync/playground/preview-schema-service.ts new file mode 100644 index 0000000000..f1423fc82a --- /dev/null +++ b/lib/services/livesync/playground/preview-schema-service.ts @@ -0,0 +1,54 @@ +import { PubnubKeys } from "./preview-app-constants"; + +export class PreviewSchemaService implements IPreviewSchemaService { + private previewSchemas: IDictionary = { + "nsplay": { + name: "nsplay", + scannerAppId: "org.nativescript.play", + scannerAppStoreId: "1263543946", + previewAppId: "org.nativescript.preview", + previewAppStoreId: "1264484702", + msvKey: "cli", + publishKey: PubnubKeys.PUBLISH_KEY, + subscribeKey: PubnubKeys.SUBSCRIBE_KEY, + default: true + }, + "ksplay": { + name: "ksplay", + scannerAppId: "com.kinvey.scanner", + scannerAppStoreId: "1263543946", + previewAppId: "com.kinvey.preview", + previewAppStoreId: "1264484702", + msvKey: "kinveyStudio", + publishKey: PubnubKeys.PUBLISH_KEY, + subscribeKey: PubnubKeys.SUBSCRIBE_KEY + } + }; + + constructor(private $errors: IErrors, + private $projectDataService: IProjectDataService) { } + + public getSchemaData(projectDir: string): IPreviewSchemaData { + let schemaName = this.getSchemaNameFromProject(projectDir); + if (!schemaName) { + schemaName = _.findKey(this.previewSchemas, previewSchema => previewSchema.default); + } + + const result = this.previewSchemas[schemaName]; + if (!result) { + this.$errors.failWithoutHelp(`Invalid schema. The valid schemas are ${_.keys(this.previewSchemas)}.`); + } + + return result; + } + + private getSchemaNameFromProject(projectDir: string): string { + try { + const projectData = this.$projectDataService.getProjectData(projectDir); + return projectData.previewAppSchema; + } catch (err) { /* ignore the error */ } + + return null; + } +} +$injector.register("previewSchemaService", PreviewSchemaService); diff --git a/lib/services/livesync/playground/preview-sdk-service.ts b/lib/services/livesync/playground/preview-sdk-service.ts index fc9565184a..63e805b067 100644 --- a/lib/services/livesync/playground/preview-sdk-service.ts +++ b/lib/services/livesync/playground/preview-sdk-service.ts @@ -1,5 +1,4 @@ import { MessagingService, Config, Device, DeviceConnectedMessage, SdkCallbacks, ConnectedDevices, FilesPayload } from "nativescript-preview-sdk"; -import { PubnubKeys } from "./preview-app-constants"; import { EventEmitter } from "events"; const pako = require("pako"); @@ -13,24 +12,20 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic private $logger: ILogger, private $previewDevicesService: IPreviewDevicesService, private $previewAppLogProvider: IPreviewAppLogProvider, - private $projectDataService: IProjectDataService) { + private $previewSchemaService: IPreviewSchemaService) { super(); } public getQrCodeUrl(options: IGetQrCodeUrlOptions): string { const { projectDir, useHotModuleReload } = options; - const projectData = this.$projectDataService.getProjectData(projectDir); - const schema = projectData.previewAppSchema || "nsplay"; - // TODO: Use the correct keys for the schema - const publishKey = PubnubKeys.PUBLISH_KEY; - const subscribeKey = PubnubKeys.SUBSCRIBE_KEY; + const schema = this.$previewSchemaService.getSchemaData(projectDir); const hmrValue = useHotModuleReload ? "1" : "0"; - const result = `${schema}://boot?instanceId=${this.instanceId}&pKey=${publishKey}&sKey=${subscribeKey}&template=play-ng&hmr=${hmrValue}`; + const result = `${schema.name}://boot?instanceId=${this.instanceId}&pKey=${schema.publishKey}&sKey=${schema.subscribeKey}&template=play-ng&hmr=${hmrValue}`; return result; } - public async initialize(getInitialFiles: (device: Device) => Promise): Promise { - const initConfig = this.getInitConfig(getInitialFiles); + public async initialize(projectDir: string, getInitialFiles: (device: Device) => Promise): Promise { + const initConfig = this.getInitConfig(projectDir, getInitialFiles); this.messagingService = new MessagingService(); this.instanceId = await this.messagingService.initialize(initConfig); } @@ -51,15 +46,18 @@ export class PreviewSdkService extends EventEmitter implements IPreviewSdkServic this.messagingService.stop(); } - private getInitConfig(getInitialFiles: (device: Device) => Promise): Config { + private getInitConfig(projectDir: string, getInitialFiles: (device: Device) => Promise): Config { + const schema = this.$previewSchemaService.getSchemaData(projectDir); + return { - pubnubPublishKey: PubnubKeys.PUBLISH_KEY, - pubnubSubscribeKey: PubnubKeys.SUBSCRIBE_KEY, - msvKey: "cli", + pubnubPublishKey: schema.publishKey, + pubnubSubscribeKey: schema.subscribeKey, + msvKey: schema.msvKey, msvEnv: this.$config.PREVIEW_APP_ENVIRONMENT, - showLoadingPage: false, callbacks: this.getCallbacks(), - getInitialFiles + getInitialFiles, + previewAppStoreId: schema.previewAppStoreId, + previewAppGooglePlayId: schema.previewAppId }; } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b8a58a5068..b32d662fac 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -141,8 +141,7 @@ "@types/node": { "version": "8.10.30", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.30.tgz", - "integrity": "sha512-Le8HGMI5gjFSBqcCuKP/wfHC19oURzkU2D+ERIescUoJd+CmNEMYBib9LQ4zj1HHEZOJQWhw2ZTnbD8weASh/Q==", - "dev": true + "integrity": "sha512-Le8HGMI5gjFSBqcCuKP/wfHC19oURzkU2D+ERIescUoJd+CmNEMYBib9LQ4zj1HHEZOJQWhw2ZTnbD8weASh/Q==" }, "@types/ora": { "version": "1.3.3", @@ -1450,13 +1449,6 @@ "integrity": "sha512-YbKCNLPPP4inc0E5If4OaalBc7gpaM2MRv77Pv2VThVComLKfbGYtJcdDCViDyp1Wd4SebhHLz94vp91zbK6bw==", "requires": { "@types/node": "^8.0.7" - }, - "dependencies": { - "@types/node": { - "version": "8.10.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.45.tgz", - "integrity": "sha512-tGVTbA+i3qfXsLbq9rEq/hezaHY55QxQLeXQL2ejNgFAxxrgu8eMmYIOsRcl7hN1uTLVsKOOYacV/rcJM3sfgQ==" - } } }, "date-format": { @@ -5353,9 +5345,9 @@ } }, "nativescript-preview-sdk": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/nativescript-preview-sdk/-/nativescript-preview-sdk-0.3.3.tgz", - "integrity": "sha512-QHi4SbDblN+dSZCIztx1xVdrB4cP911OXV92REIVOqDHXyAFYUZeWu5DH0/3IHdC9fnMgXMeJ0WZEpgGgieqtQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/nativescript-preview-sdk/-/nativescript-preview-sdk-0.3.4.tgz", + "integrity": "sha512-Dw4Nn6MXbZMW8dkQIf1NfXSSNtu3rDOw0z1KE159lwPEVMM8F7qxrqqT57XTiQP5pnqXMARhoQvkgW55qTVx6Q==", "requires": { "@types/axios": "0.14.0", "@types/pubnub": "4.0.2", diff --git a/package.json b/package.json index 84330567a7..6c85f0b322 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "mute-stream": "0.0.5", "nativescript-dev-xcode": "0.1.0", "nativescript-doctor": "1.9.2", - "nativescript-preview-sdk": "0.3.3", + "nativescript-preview-sdk": "0.3.4", "open": "0.0.5", "ora": "2.0.0", "osenv": "0.1.3", diff --git a/test/services/playground/preview-app-livesync-service.ts b/test/services/playground/preview-app-livesync-service.ts index 42f097a24e..4706a00439 100644 --- a/test/services/playground/preview-app-livesync-service.ts +++ b/test/services/playground/preview-app-livesync-service.ts @@ -73,7 +73,7 @@ class PreviewSdkServiceMock extends EventEmitter implements IPreviewSdkService { return "my_cool_qr_code_url"; } - public initialize(getInitialFiles: (device: Device) => Promise) { + public initialize(projectDir: string, getInitialFiles: (device: Device) => Promise) { this.getInitialFiles = async (device) => { const filesPayload = await getInitialFiles(device); initialFiles.push(...filesPayload.files); diff --git a/test/services/playground/preview-schema-service.ts b/test/services/playground/preview-schema-service.ts new file mode 100644 index 0000000000..b2f279c315 --- /dev/null +++ b/test/services/playground/preview-schema-service.ts @@ -0,0 +1,89 @@ +import { Yok } from "../../../lib/common/yok"; +import { PreviewSchemaService } from "../../../lib/services/livesync/playground/preview-schema-service"; +import { PubnubKeys } from "../../../lib/services/livesync/playground/preview-app-constants"; +import { assert } from "chai"; + +function createTestInjector(): IInjector { + const injector = new Yok(); + injector.register("previewSchemaService", PreviewSchemaService); + injector.register("projectDataService", () => ({})); + injector.register("errors", () => ({})); + + return injector; +} + +const nsPlaySchema = { + name: 'nsplay', + scannerAppId: 'org.nativescript.play', + scannerAppStoreId: '1263543946', + previewAppId: 'org.nativescript.preview', + previewAppStoreId: '1264484702', + msvKey: 'cli', + publishKey: PubnubKeys.PUBLISH_KEY, + subscribeKey: PubnubKeys.SUBSCRIBE_KEY, + default: true +}; + +const ksPlaySchema = { + name: 'ksplay', + scannerAppId: 'com.kinvey.scanner', + scannerAppStoreId: '1263543946', + previewAppId: 'com.kinvey.preview', + previewAppStoreId: '1264484702', + msvKey: 'kinveyStudio', + publishKey: PubnubKeys.PUBLISH_KEY, + subscribeKey: PubnubKeys.SUBSCRIBE_KEY +}; + +describe("PreviewSchemaService", () => { + let injector: IInjector; + let previewSchemaService: IPreviewSchemaService; + + beforeEach(() => { + injector = createTestInjector(); + previewSchemaService = injector.resolve("previewSchemaService"); + }); + + const testCases = [ + { + name: "should return default nsplay schema when no previewAppSchema in nsconfig", + previewAppSchema: null, + expectedSchema: nsPlaySchema + }, + { + name: "should return nsplay schema when { 'previewAppSchema': 'nsplay' } in nsconfig", + previewAppSchema: "nsplay", + expectedSchema: nsPlaySchema + }, + { + name: "should return ksplay schema when { 'previewAppSchema': 'ksplay' } in nsconfig", + previewAppSchema: "ksplay", + expectedSchema: ksPlaySchema + }, + { + name: "should throw an error when invalid previewAppSchema is specified in nsconfig", + previewAppSchema: "someInvalidSchema", + expectedToThrow: true + } + ]; + + _.each(testCases, testCase => { + it(`${testCase.name}`, () => { + const projectDataService = injector.resolve("projectDataService"); + projectDataService.getProjectData = () => ({ previewAppSchema: testCase.previewAppSchema }); + + let actualError = null; + if (testCase.expectedToThrow) { + const errors = injector.resolve("errors"); + errors.failWithoutHelp = (err: string) => actualError = err; + } + + const schemaData = previewSchemaService.getSchemaData("someTestProjectDir"); + + assert.deepEqual(schemaData, testCase.expectedSchema); + if (testCase.expectedToThrow) { + assert.isNotNull(actualError); + } + }); + }); +}); diff --git a/test/services/preview-sdk-service.ts b/test/services/preview-sdk-service.ts index c129ead91d..98a82b8b9e 100644 --- a/test/services/preview-sdk-service.ts +++ b/test/services/preview-sdk-service.ts @@ -2,6 +2,7 @@ import { PreviewSdkService } from "../../lib/services/livesync/playground/previe import { Yok } from "../../lib/common/yok"; import { assert } from "chai"; import { LoggerStub } from "../stubs"; +import { PreviewSchemaService } from "../../lib/services/livesync/playground/preview-schema-service"; const createTestInjector = (): IInjector => { const testInjector = new Yok(); @@ -9,6 +10,7 @@ const createTestInjector = (): IInjector => { testInjector.register("config", {}); testInjector.register("previewSdkService", PreviewSdkService); testInjector.register("previewDevicesService", {}); + testInjector.register("previewSchemaService", PreviewSchemaService); testInjector.register("previewAppLogProvider", {}); testInjector.register("httpClient", { httpRequest: async (options: any, proxySettings?: IProxySettings): Promise => undefined @@ -16,6 +18,7 @@ const createTestInjector = (): IInjector => { testInjector.register("projectDataService", { getProjectData: () => ({}) }); + testInjector.register("errors", {}); return testInjector; }; diff --git a/yarn.lock b/yarn.lock index c03c36e661..d613daa50b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3731,10 +3731,10 @@ nativescript-doctor@1.9.2: winreg "1.2.2" yauzl "2.10.0" -nativescript-preview-sdk@0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/nativescript-preview-sdk/-/nativescript-preview-sdk-0.3.3.tgz#0e95e5a92db8d4566d9bb9767a2a849217574787" - integrity sha512-QHi4SbDblN+dSZCIztx1xVdrB4cP911OXV92REIVOqDHXyAFYUZeWu5DH0/3IHdC9fnMgXMeJ0WZEpgGgieqtQ== +nativescript-preview-sdk@0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/nativescript-preview-sdk/-/nativescript-preview-sdk-0.3.4.tgz#bb0dc3ce7da2be7e1e91cd2836b61b3699555f95" + integrity sha512-Dw4Nn6MXbZMW8dkQIf1NfXSSNtu3rDOw0z1KE159lwPEVMM8F7qxrqqT57XTiQP5pnqXMARhoQvkgW55qTVx6Q== dependencies: "@types/axios" "0.14.0" "@types/pubnub" "4.0.2"