簡報: https://goo.gl/HPpyka
Wifi SSID: trunk-studio
Wifi 密碼 8 個 0
上課環境:ftp://192.168.23.1
寫一份程式碼
即可達成跨平台 App 開發建置與維護。
骨子裡還是網頁
官方 market 有賣 theme、pulgin
適合有網頁開發底子,要簡單 MVP 的產品
Angular, TypeScript, JavaScript
適合熟悉 Angular 的開發者
也有官方的 Market
可擴展現有 APP
Vue 版本 preview 中
適合熟悉物件導向的程式語言開發者的垮平台解決方案
分為社區版、專業版、企業版
最近剛發佈的 Google 跨平台 APP 解決方案
使用 Dart 語言開發
Beta 中,還在觀望
Html, CSS, JavaScript
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash
設定環境變數 (~/.bash_profile, ~/.zshrc, ~/.profile, or ~/.bashrc)
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm
source ~/.bashrc
nvm install 8
React Native 目前需要 Android Studio2.0 或更高版本。
SDK Platforms 選擇 Google APIs 、 Android SDK Platform 23
確保 ANDROID_HOME 環境變數跟 SDK 路徑一致。
Windows
控制台 > 系統及安全性 > 進階系統設定 > 進階 > 環境變數 > 新增
控制台 > 系統及安全性 > 進階系統設定 > 進階 > 環境變數 > 選擇 PATH > 編輯 在後方新增
;C:\Users\使用者名稱\AppData\Local\Android\sdk\platform-tools;C:\Users
\使用者名稱\AppData\Local\Android\sdk\tools
Mac 開起 ~/.bashrc 或 ~/.zshrc 或 ~/.profile 在最後加上
export ANDROID_HOME=${HOME}/Library/Android/sdk
export PATH=${PATH}:${ANDROID_HOME}/tools
export PATH=${PATH}:${ANDROID_HOME}/platform-tools
npm install --save-dev babel-eslint eslint-config-airbnb-base
eslint-plugin-react eslint-plugin-react-native
node_modules/.bin/eslint --init
選擇 style
? How would you like to configure ESLint? Use a popular style guide
? Which style guide do you want to follow? Airbnb
? Do you use React? Yes
? What format do you want your config file to be in? JavaScript
常見 Code Style 提醒
// bad
var count = 1;
if (true) {
count += 1;
}
// good, use the let.
let count = 1;
if (true) {
count += 1;
}
// bad
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';
// good
import AirbnbStyleGuide from './AirbnbStyleGuide';
Create React Native App
npm install -g create-react-native-app
create-react-native-app AwesomeProject
cd AwesomeProject
npm start
環境使用教學影片 注意有先後順序之分
在 本機 電腦執行命令提示字元執行指令
$ adb devices
$ adb tcpip 5556
$ adb connect $ip:5556
/* $ip 請自行替換為 adb devices 回傳的 Android 虛擬機 IP
例如: adb connect 192.168.57.101:5556 */
$ adb devices
/* 測試是否有連上 */
$ adb shell am start -a android.settings.SETTINGS
$ npm install -g react-native-cli
$ react-native init demo
$ cd demo
$ npm start
$ react-native run-android
react-native init ${project name} --template ${template name}
react-native init ${project name} --template file:///path_to/react-native-template-XXXX
react-native init ${project name} --template git://.../react-native-template-XXXX
adb install ./android/app/build/outputs/apk/app-debug.apk
.
├── App.js
├── __tests__
├── android
├── app.json
├── index.js
├── ios
├── node_modules
├── package.json
└── yarn.lock
App 名稱位置 :
./android/app/src/main/res/values/strings.xml
./android/app/src/main/res/mipmap-*
App icon:
開啟開發人員選單
Debug JS Remote
reload
跟 Server 獲取、提交資料的方法
提供了和 web 標準一至的 Fetch API
安全機制與網頁不同,在 RN 中沒有 CROS 的限制
async function getMoviesFromApi() {
try {
let response = await fetch(
'https://facebook.github.io/react-native/movies.json'
);
let responseJson = await response.json();
return responseJson.movies;
} catch (error) {
console.error(error);
}
}
getMoviesFromApiAsync() {
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
}
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>rn.fuyaode.me</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
handleConnectivityChange = async (isConnected) => {
....
}
NetInfo.addEventListener(
'connectionChange',
this.handleConnectivityChange
);
Android 記得加上權限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
if (__DEV__) {
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest
}
getData = async (page) => {
try {
let response = await fetch(`http://rn.fuyaode.me/users/1`);
let responseJson = await response.json();
console.log(responseJson);
this.setState({
name: responseJson.name
})
return responseJson;
} catch (e) {
console.error(e);
}
}
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
const formData = new FormData();
form.append('id', 'A123123123');
form.append('password', '0000');
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
},
body: formData,
});
const formData = new FormData();
formData.append('file', {
uri: filepath,
type: `${fileType}/${ext}`,
name: fileName,
})
fetch('https://s3.us-east-2.amazonaws.com/test.png', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: formData,
});
選擇圖片、影片
cosnt options = {
title: '選擇頭貼',
storageOptions: {
skipBackup: true,
path: 'images'
}
};
ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
let source = { uri: response.uri };
this.setState({
avatarSource: source
});
}
});
RNThumbnail.get(filepath).then((result) => {
console.log(result.path);
})
<Image source={{uri : this.state.videoUri}} />
Image 原生元件支援顯示 Video 縮圖
import {
AudioPlayer,
AudioRecorder,
AudioUtils,
} from 'react-native-audio-player-recorder';
AudioRecorder.prepareRecordingAtPath(
AudioUtils.DocumentDirectoryPath + '/record.aac', {
SampleRate: 22050,
Channels: 1,
AudioQuality: 'Low',
AudioEncoding: 'aac',
AudioEncodingBitRate: 32000
}
);
AudioRecorder.startRecording();
檢查檔案大小
import RNFS from 'react-native-fs';
const fileStat = await RNFS.stat(filepath);
if (fileStat.size < 1024 * 1024 * 50) {
...
} else {
// 檔案超過限制大小
}
var ws = new WebSocket('ws://host.com/path');
ws.onopen = () => {
// connection opened
ws.send('something'); // send a message
};
ws.onmessage = (e) => {
// a message was received
console.log(e.data);
};
ws.onerror = (e) => {
// an error occurred
console.log(e.message);
};
ws.onclose = (e) => {
// connection closed
console.log(e.code, e.reason);
};