diff --git a/README.md b/README.md index e24e6ab..f4106a8 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ ReactTV.render(, document.getElementById('root')) - [About React-TV](#about-react-tv) - [Understanding the Problem](#understanding-the-problem) + - [Setup for TV SKDs](#setup-for-tv-sdks) - [Articles](#articles) - [react-tv-cli](#react-tv-cli) - [Developing for WebOS](#developing-for-webos) @@ -72,6 +73,11 @@ These restrictions make super responsive 60fps experiences especially tricky. Th In addition: Unify the build for multiple TV platforms. +### Setup for TV SKDs + +- [Setup LG WebOS SDK](docs/setup-webos-environment.md) +- [Setup Samsung Tizen SDK](docs/setup-tizen-environment.md) + ### Articles Friendly list of tutorials and articles: @@ -240,6 +246,16 @@ See [examples/navigation](examples/navigation) for more details about usage. - http://webostv.developer.lge.com/develop/app-developer-guide/web-app-lifecycle/ - http://webostv.developer.lge.com/develop/js-services/calling-js-service/ +### Tizen + +- http://developer.samsung.com/tv/develop/tools/tizen-studio +- http://developer.samsung.com/tv/develop/getting-started/setting-up-sdk/installing-tv-sdk +- http://developer.samsung.com/tv/develop/getting-started/setting-up-sdk/creating-certificates +- http://developer.samsung.com/tv/develop/getting-started/creating-tv-applications +- http://developer.samsung.com/tv/design/design-principles +- http://developer.samsung.com/tv/develop/specifications/general-specifications +- http://developer.samsung.com/tv/develop/specifications/web-engine-specifications + #### Videos ##### Windows @@ -252,7 +268,6 @@ See [examples/navigation](examples/navigation) for more details about usage. ### Essentials to beginner -- http://developer.samsung.com/tv/develop/getting-started/setup-sdk/installing-tv-sdk/ - http://developer.samsung.com/tv/develop/getting-started/using-sdk/tv-simulator - http://developer.samsung.com/tv/develop/getting-started/essentials-for-beginner @@ -289,7 +304,7 @@ Implement essential functionality needed for daily use by early adopters. - [ ] Support render to Canvas instead DOM using `React.CanvasComponent` - [x] `run-webos` support TV device as param - [ ] Optmizate DOMRenderer for TV -- [ ] Start CLI for Tizen +- [x] Start CLI for Tizen - [x] Develop helpers for WebOS debbug (e.g: Log System). - [x] Support Cross Platform - [x] Check executable bin path for Windows, OSX and Linux @@ -307,7 +322,7 @@ Add additional features users expect from a Renderer. Then fix bugs and stabiliz - [ ] Reactive Renderer - [ ] Testing and stability ----------------------------------------------------- +---------------------------------------------------- See ReactTV's [Changelog](https://github.com/raphamorim/react-tv/blob/master/CHANGELOG.md). diff --git a/docs/setup-tizen-environment.md b/docs/setup-tizen-environment.md new file mode 100644 index 0000000..2456155 --- /dev/null +++ b/docs/setup-tizen-environment.md @@ -0,0 +1,13 @@ +# Setup Tizen Environment + +Alternative guides: + +- [Developing for “old” Samsung TVs in Tizen Studio 2.x](https://medium.com/@ibazzva/developing-for-old-samsung-tvs-in-tizen-studio-2-x-5aa3f853db09) + +[Install the Tizen Studio](http://developer.samsung.com/tv/develop/tools/tizen-studio) + +[Install Tizen Studio 2.1](http://download.tizen.org/sdk/Installer/tizen-studio_2.1/) + +[Install the TV SDK](http://developer.samsung.com/tv/develop/getting-started/setting-up-sdk/installing-tv-sdk/) + +Using the Package Manager install the Web CLI, Native CLI and Baseline SDK packages under the Tizen SDK Tools diff --git a/docs/setup-webos-environment.md b/docs/setup-webos-environment.md index 7333004..384ab66 100644 --- a/docs/setup-webos-environment.md +++ b/docs/setup-webos-environment.md @@ -24,6 +24,12 @@ Execute your Installer (If you're in Linux or Mac the Installer will ask for be ![Executing OSX Installer](resources/webos/1-executing-osx-installer.png) +For OSX: Note if you doesn’t have `/opt` folder, you must to create manual. + +```bash +sudo mkdir /opt +``` + You pop the SDK Installer, select "Agree" about LG Agreement and choose the destination folder for this installation to continue. ![WebOS Introduction](resources/webos/2-webos-introduction.png) @@ -39,3 +45,5 @@ You'll install all packages. After installation step, restart your machine. ![WebOS Complete](resources/webos/5-webos-complete.png) + +SDK Installed! diff --git a/examples/clock-app/README.md b/examples/clock-app/README.md index 1963c4e..a20ab62 100644 --- a/examples/clock-app/README.md +++ b/examples/clock-app/README.md @@ -20,8 +20,15 @@ yarn To run it: +WebOS: ```shell yarn start ``` +Tizen: +```shell +yarn start-tizen +``` + + ![Screenshot](screenshot.png) diff --git a/examples/clock-app/src/App.js b/examples/clock-app/src/App.js index 1bf47ae..bf3df5b 100644 --- a/examples/clock-app/src/App.js +++ b/examples/clock-app/src/App.js @@ -16,6 +16,9 @@ class Clock extends React.Component { if (Platform('webos')) currentPlatform = 'LG WebOS' + if (Platform('tizen')) + currentPlatform = 'Samsung Tizen' + return (
diff --git a/examples/navigation/README.md b/examples/navigation/README.md index e7c9b5f..c3dcaf9 100644 --- a/examples/navigation/README.md +++ b/examples/navigation/README.md @@ -26,6 +26,12 @@ yarn start-dev To run it on TV WebOS: +WebOS: ```shell -yarn start +yarn start-webos +``` + +Tizen: +```shell +yarn start-tizen ``` diff --git a/examples/navigation/package.json b/examples/navigation/package.json index 6d5aa6f..d21e68e 100644 --- a/examples/navigation/package.json +++ b/examples/navigation/package.json @@ -13,9 +13,10 @@ }, "scripts": { "build": "webpack", - "build-prod": "NODE_ENV=production yarn build", + "build-prod": "cross-env NODE_ENV=production yarn build", "react-tv-cli": "react-tv-cli", "start": "yarn build-prod && react-tv-cli run-webos", + "start-tizen": "yarn build && react-tv run-tizen", "start-dev": "webpack-dev-server --progress --colors" }, "dependencies": { @@ -29,6 +30,7 @@ "babel-loader": "^6.2.1", "babel-polyfill": "^6.26.0", "babel-preset-react": "^6.3.13", + "cross-env": "^5.1.1", "webpack": "^1.12.12", "webpack-dev-server": "^1.12.1" } diff --git a/packages/react-tv-cli/bootstrap/react-tv/tizen/config.xml b/packages/react-tv-cli/bootstrap/react-tv/tizen/config.xml new file mode 100644 index 0000000..a05f053 --- /dev/null +++ b/packages/react-tv-cli/bootstrap/react-tv/tizen/config.xml @@ -0,0 +1,12 @@ + + + + {{REACTTVAPP}} + + + + + + + + diff --git a/packages/react-tv-cli/index.js b/packages/react-tv-cli/index.js index 6bde05d..2a9760c 100755 --- a/packages/react-tv-cli/index.js +++ b/packages/react-tv-cli/index.js @@ -2,7 +2,7 @@ const argv = process.argv; const {help, version, createReactTVApp} = require('./shared'); -const {WebOS} = require('./scripts'); +const {WebOS, Tizen} = require('./scripts'); if (argv.length < 2) { return help(); @@ -41,6 +41,14 @@ switch (command) { WebOS.getKey(device); break; + case 'run-tizen': + if (argv.length > 3) { + device = argv[3]; + } + + Tizen.run(process.cwd()); + break; + case '--version': version(); break; diff --git a/packages/react-tv-cli/package.json b/packages/react-tv-cli/package.json index e8accb5..118ce91 100644 --- a/packages/react-tv-cli/package.json +++ b/packages/react-tv-cli/package.json @@ -16,7 +16,8 @@ "chalk": "^2.1.0", "fs-extra": "^4.0.3", "node-replace": "^0.3.1", - "node-webos": "^0.3.0" + "node-webos": "^0.3.0", + "randomstring": "^1.1.5" }, "repository": { "type": "git", diff --git a/packages/react-tv-cli/scripts/tizen/index.js b/packages/react-tv-cli/scripts/tizen/index.js new file mode 100644 index 0000000..503717d --- /dev/null +++ b/packages/react-tv-cli/scripts/tizen/index.js @@ -0,0 +1,5 @@ +const run = require('./run'); + +module.exports = { + run, +}; diff --git a/packages/react-tv-cli/scripts/tizen/run.js b/packages/react-tv-cli/scripts/tizen/run.js new file mode 100644 index 0000000..7b77d7f --- /dev/null +++ b/packages/react-tv-cli/scripts/tizen/run.js @@ -0,0 +1,177 @@ +const path = require('path'); +const fs = require('fs-extra'); +const chalk = require('chalk'); +const execSync = require('child_process').execSync; + +function defaultCLIEnv() { + //return '/opt/tizen/tools/ide/bin'; + return 'E:/Ferramentas/tizen/tools/ide/bin'; +} + +function getPackageId(root) { + const appinfo = path.resolve(root, 'react-tv/tizen/config.xml'); + const content = fs.readFileSync(appinfo, {encoding: 'utf-8'}); + + const re = new RegExp(/tizen:application id="(.*?)"/); + const matches = content.match(re); + + if (!matches) { + return null; + } + + return matches[1]; +} + +function isReactTVTizenProject(root) { + const appinfo = path.resolve(root, 'react-tv/tizen/config.xml'); + if (fs.existsSync(appinfo)) { + return true; + } + return false; +} + +function run(root) { + let tizen_CLI_ENV = process.env.TIZEN_CLI || false; + if (!tizen_CLI_ENV) { + tizen_CLI_ENV = defaultCLIEnv(); + } + + process.env.PATH = `${tizen_CLI_ENV}:${process.env.PATH}`; + + if (!isReactTVTizenProject(root)) { + const msg = `This project isn\'t a React-TV Tizen Project: + Just run "react-tv init"`; + return console.log(chalk.dim('[react-tv]'), msg); + } + + const packageJson = require(path.resolve(root, 'package.json')); + const ReactTVConfig = packageJson['react-tv']; + if (!ReactTVConfig) { + return console.log( + chalk.dim('[react-tv]'), + 'You should set react-tv properties on package.json' + ); + } + + if (!ReactTVConfig.files || !ReactTVConfig.files.length) { + return console.log(chalk.dim('[react-tv]'), 'You should add files'); + } + + // TODO: option to create/select profiles? + const securityProfiles = execSync( + `${tizen_CLI_ENV}/tizen security-profiles list` + ) + .toString() + .trim() + .split('\n'); + if (!securityProfiles) { + return console.log( + chalk.dim('[react-tv]'), + 'No tizen security profiles found' + ); + } + + // Select the last profile + const selectedProfile = securityProfiles[securityProfiles.length - 1] + .split(' ', 1)[0] + .trim(); + + const tizenPath = path.resolve(root, 'react-tv/tizen'); + + process.on('exit', cleanup); + process.on('SIGINT', cleanup); + process.on('SIGUSR1', cleanup); + process.on('SIGUSR2', cleanup); + process.on('uncaughtException', cleanup); + + function cleanup() { + fs.removeSync(`${tizenPath}/icon.png`); + ReactTVConfig.files.forEach(file => { + fs.removeSync(`${tizenPath}/${file}`); + }); + } + + try { + cleanup(); + fs.copySync(`${root}/react-tv/icon-large.png`, `${tizenPath}/icon.png`); + + ReactTVConfig.files.forEach(file => { + const filePath = path.resolve(root, file); + const toFile = path.resolve(tizenPath, file); + fs.ensureDirSync(path.dirname(toFile)); + fs.copySync(`${filePath}`, `${toFile}`); + }); + } catch (e) { + return console.log('FAIL TO MOUNT', e.toString()); + } + + console.log(''); + console.log(chalk.dim('Setting up Emulator...')); + + const vms = execSync( + `${tizen_CLI_ENV}/../../emulator/bin/em-cli list-vm` + ).toString(); + + if (vms.indexOf('react-tv-tizen') < 0) { + execSync( + `${tizen_CLI_ENV}/../../emulator/bin/em-cli create -n react-tv-tizen -p tv-samsung-3.0-x86` + ); + } + + const runningVms = execSync(`${tizen_CLI_ENV}/../../sdb devices`).toString(); + + if (runningVms.indexOf('react-tv-tizen') < 0) { + console.log(chalk.dim('Running Emulator...')); + execSync( + `${tizen_CLI_ENV}/../../emulator/bin/em-cli launch -n react-tv-tizen` + ); + console.log(chalk.yellow(' Tizen Emulator successful running')); + } else { + console.log(chalk.yellow(' already running.')); + } + + console.log(chalk.dim('Packing...')); + execSync( + `cd ${tizenPath} && ${tizen_CLI_ENV}/tizen package -t wgt -s ${selectedProfile}` + ); + console.log(chalk.yellow(` succefull pack from ${root}`)); + + console.log(chalk.dim('Running App...')); + + let attemps = 0; + const task = setInterval(function() { + if (attemps > 15) { + console.log('FAILED TO UP Tizen emulator'); + clearInterval(task); + } + + try { + execSync(`${tizen_CLI_ENV}/../../sdb devices`).toString(); + + execSync( + `cd ${tizenPath} && ${tizen_CLI_ENV}/tizen install -n ${ + packageJson.name + }.wgt -t react-tv-tizen` + ); + } catch (error) { + if (error.stdout.toString().indexOf('install completed') < 0) { + attemps += 1; + return false; + } + } + + clearInterval(task); + + const packageId = getPackageId(root); + + if (!packageId) { + return console.log('Invalid package id!'); + } + + execSync( + `cd ${tizenPath} && ${tizen_CLI_ENV}/tizen run -p ${packageId} -t react-tv-tizen` + ); + }, 500); +} + +module.exports = run; diff --git a/packages/react-tv-cli/shared/index.js b/packages/react-tv-cli/shared/index.js index add9c2a..2b88cca 100644 --- a/packages/react-tv-cli/shared/index.js +++ b/packages/react-tv-cli/shared/index.js @@ -2,6 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const chalk = require('chalk'); const replace = require('node-replace'); +const randomstring = require('randomstring'); function debug(msg) { console.log(chalk.dim('[react-tv]'), msg); @@ -48,6 +49,7 @@ https://medium.com/@raphamorim/developing-for-tvs-with-react-tv-b5b5204964ef`) } function createReactTVApp(appName) { + console.log('tizen'); let appPath = process.cwd(); const packageJson = path.resolve(appPath, 'package.json'); @@ -66,6 +68,22 @@ function createReactTVApp(appName) { recursive: true, silent: true, }); + + replace({ + regex: '{{TIZEN_PACKAGE}}', + replacement: randomstring.generate(10), + paths: [appName], + recursive: true, + silent: true, + }); + + replace({ + regex: '{{TIZEN_REACTTVAPP}}', + replacement: appName.replace(/-/g, '').replace(/\./g, ''), + paths: [appName], + recursive: true, + silent: true, + }); } catch (e) { return process.exit(1); } @@ -96,6 +114,22 @@ function createReactTVApp(appName) { recursive: true, silent: true, }); + + replace({ + regex: '{{TIZEN_PACKAGE}}', + replacement: randomstring.generate(10), + paths: ['./react-tv/tizen'], + recursive: true, + silent: true, + }); + + replace({ + regex: '{{TIZEN_REACTTVAPP}}', + replacement: appName.replace(/-/g, '').replace(/\./g, ''), + paths: ['./react-tv/tizen'], + recursive: true, + silent: true, + }); } catch (e) { return process.exit(1); } diff --git a/packages/react-tv/modules/Platform.js b/packages/react-tv/modules/Platform.js index c700f52..7c91a7e 100644 --- a/packages/react-tv/modules/Platform.js +++ b/packages/react-tv/modules/Platform.js @@ -12,7 +12,7 @@ function isLGWebOS() { } function isSamsungTizen() { - return false; + return !!(window && window.tizen); } function isSamsungOrsay() {