Browse Source

add samples readme

matrixbirds 5 years ago
parent
commit
36cc4a2ed3

+ 3
- 0
.gitignore View File

@@ -55,3 +55,6 @@ android/src/main/res/drawable/
55 55
 **/*.*~
56 56
 **/*.swp
57 57
 **/*.~
58
+.project
59
+.settings
60
+.classpath

+ 5
- 0
samples/README.md View File

@@ -0,0 +1,5 @@
1
+# react native agora samples
2
+
3
+| name | description |
4
+| :-------------: | :-------------: |
5
+| [simpleDemo](./simpleDemo) | react-native-agora demo for beginner |

+ 9
- 2
samples/simpleDemo/App.js View File

@@ -57,7 +57,8 @@ export default class App extends Component<Props> {
57 57
       channelProfile: 1,
58 58
       videoProfile: 40,
59 59
       clientRole: 1,
60
-      swapWidthAndHeight: true
60
+      swapWidthAndHeight: true,
61
+      channelName: 'defaultChannel'
61 62
     };
62 63
   }
63 64
 
@@ -83,6 +84,7 @@ export default class App extends Component<Props> {
83 84
         videoProfile={this.state.videoProfile}
84 85
         clientRole={this.state.clientRole}
85 86
         swapWidthAndHeight={this.state.swapWidthAndHeight}
87
+        channelName={this.state.channelName}
86 88
       ></AgoraRTCView>);
87 89
     }
88 90
     return (
@@ -119,6 +121,11 @@ export default class App extends Component<Props> {
119 121
               this.setState({clientRole: +matched})
120 122
             }          }
121 123
         } />
124
+        <TextInput
125
+          style={{height: 40}}
126
+          placeholder="Enter channelName"
127
+          onChnageText={(text) => this.setState({channelName: text})}
128
+        />
122 129
         <TouchableOpacity
123 130
           style={styles.button}
124 131
           onPress={this.joinChannel}
@@ -128,4 +135,4 @@ export default class App extends Component<Props> {
128 135
       </View>
129 136
     );
130 137
   }
131
-}
138
+}

+ 35
- 1
samples/simpleDemo/README.md View File

@@ -17,6 +17,40 @@
17 17
   npm install
18 18
   npm run android
19 19
   ```
20
+## Build Signed App
21
+### Generate keystore file.
22
+
23
+  ```bash
24
+    keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
25
+  ```
26
+### Edit android/app/build.gradle
27
+
28
+  ```java
29
+    signingConfigs {
30
+        release {
31
+            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
32
+                storeFile file(MYAPP_RELEASE_STORE_FILE)
33
+                storePassword MYAPP_RELEASE_STORE_PASSWORD
34
+                keyAlias MYAPP_RELEASE_KEY_ALIAS
35
+                keyPassword MYAPP_RELEASE_KEY_PASSWORD
36
+            }
37
+        }
38
+    }
39
+  ```
40
+
41
+### Edit android/gradle.properties
42
+
43
+  ```
44
+  MYAPP_RELEASE_STORE_FILE=my-release-key.keystore # your keystore file name
45
+  MYAPP_RELEASE_KEY_ALIAS=my-key-alias # key alias
46
+  MYAPP_RELEASE_STORE_PASSWORD=****** # password
47
+  MYAPP_RELEASE_KEY_PASSWORD=****** # password confirm
48
+  ```
49
+
50
+### Build
51
+  ```
52
+  npm run build-android
53
+  ```
20 54
 
21 55
 # iOS Setup
22 56
 
@@ -31,4 +65,4 @@
31 65
   ```bash
32 66
   npm install
33 67
   npm run ios
34
-  ```
68
+  ```

+ 167
- 158
samples/simpleDemo/components/agora.js View File

@@ -1,12 +1,13 @@
1 1
 import React, {Component, PureComponent} from 'react';
2 2
 import {
3 3
   StyleSheet, Text, View, TouchableOpacity,
4
-  Image, Dimensions, Modal
4
+  Image, Dimensions, Modal, Platform
5 5
 } from 'react-native';
6 6
 
7 7
 import {RtcEngine, AgoraView} from 'react-native-agora';
8 8
 import {
9 9
   APPID,
10
+  isIphoneX, isIphoneXR
10 11
 } from '../utils';
11 12
 
12 13
 const BtnEndCall = () => require('../assets/btn_endcall.png');
@@ -19,9 +20,14 @@ const DisableCamera = () => require('../assets/disable_camera.png');
19 20
 const EnablePhotoflash = () => require('../assets/enable_photoflash.png');
20 21
 const DisablePhotoflash = () => require('../assets/disable_photoflash.png');
21 22
 const IconMuted = () => require('../assets/icon_muted.png');
22
-const IconSpeaker = () =>require('../assets/icon_speaker.png');
23
+const IconSpeaker = () => require('../assets/icon_speaker.png');
23 24
 
24
-const {width} = Dimensions.get('window');
25
+const {width, height} = Dimensions.get('window');
26
+
27
+const safeTop = (top) => (isIphoneX(Platform, width, height) ?
28
+  (top + 88) :
29
+  (isIphoneXR(Platform, width, height) ? ( top + 64 ) : top)
30
+);
25 31
 
26 32
 const styles = StyleSheet.create({
27 33
   container: {
@@ -30,7 +36,7 @@ const styles = StyleSheet.create({
30 36
   },
31 37
   absView: {
32 38
     position: 'absolute',
33
-    top: 20,
39
+    top: safeTop(0),
34 40
     left: 0,
35 41
     right: 0,
36 42
     bottom: 0,
@@ -77,6 +83,7 @@ class OperateButton extends PureComponent {
77 83
 
78 84
 type Props = {
79 85
   channelProfile: Number,
86
+  channelName: String,
80 87
   videoProfile: Number,
81 88
   clientRole: Number,
82 89
   swapWidthAndHeight: Boolean,
@@ -113,17 +120,12 @@ export default class Agora extends Component<Props> {
113 120
       console.log('[RtcEngine] getSdkVersion', version);
114 121
     })
115 122
 
116
-    RtcEngine.joinChannel();
123
+    console.log('[joinChannel] ' + this.props.channelName);
124
+    RtcEngine.joinChannel(this.props.channelName);
117 125
     RtcEngine.enableAudioVolumeIndication(500, 3);
118 126
     RtcEngine.eventEmitter({
119 127
       onFirstRemoteVideoDecoded: (data) => {
120 128
         console.log('[RtcEngine] onFirstRemoteVideoDecoded', data);
121
-        const {peerIds} = this.state;
122
-        if (peerIds.indexOf(data.uid) !== -1) {
123
-          this.setState({
124
-            peerIds: [...peerIds, data.uid]
125
-          })
126
-        }
127 129
       },
128 130
       onUserOffline: (data) => {
129 131
         console.log('[RtcEngine] onUserOffline', data);
@@ -144,6 +146,12 @@ export default class Agora extends Component<Props> {
144 146
       },
145 147
       onUserJoined: (data) => {
146 148
         console.log('[RtcEngine] onUserJoined', data);
149
+        const {peerIds} = this.state;
150
+        if (peerIds.indexOf(data.uid) !== -1) {
151
+          this.setState({
152
+            peerIds: [...peerIds, data.uid]
153
+          })
154
+        }
147 155
       },
148 156
       onError: (data) => {
149 157
         console.log('[RtcEngine] onError', data);
@@ -156,171 +164,172 @@ export default class Agora extends Component<Props> {
156 164
     })
157 165
   }
158 166
 
159
-componentWillUnmount () {
160
-  RtcEngine.removeEmitter()
161
-}
167
+  componentWillUnmount () {
168
+    RtcEngine.removeEmitter()
169
+  }
162 170
 
163
-handleCancel = () => {
164
-  RtcEngine.leaveChannel();
165
-  RtcEngine.destroy();
166
-  this.props.onCancel();
167
-}
171
+  handleCancel = () => {
172
+    RtcEngine.leaveChannel();
173
+    RtcEngine.destroy();
174
+    this.props.onCancel();
175
+  }
168 176
 
169
-switchCamera = () => {
170
-  RtcEngine.switchCamera();
171
-}
177
+  switchCamera = () => {
178
+    RtcEngine.switchCamera();
179
+  }
172 180
 
173
-toggleAllRemoteAudioStreams = () => {
174
-  this.setState({
175
-    isMute: !this.state.isMute
176
-  }, () => {
177
-    RtcEngine.muteAllRemoteAudioStreams(this.state.isMute);
178
-  })
179
-}
181
+  toggleAllRemoteAudioStreams = () => {
182
+    this.setState({
183
+      isMute: !this.state.isMute
184
+    }, () => {
185
+      RtcEngine.muteAllRemoteAudioStreams(this.state.isMute);
186
+    })
187
+  }
180 188
 
181
-toggleSpeakerPhone = () => {
182
-  this.setState({
183
-    isSpeak: !this.state.isSpeak
184
-  }, () => {
185
-    RtcEngine.setDefaultAudioRouteToSpeakerphone(this.state.isSpeak);
186
-  })
187
-}
189
+  toggleSpeakerPhone = () => {
190
+    this.setState({
191
+      isSpeak: !this.state.isSpeak
192
+    }, () => {
193
+      RtcEngine.setDefaultAudioRouteToSpeakerphone(this.state.isSpeak);
194
+    })
195
+  }
188 196
 
189
-toggleCameraTorch = () => {
190
-  this.setState({
191
-    isCameraTorch: !this.state.isCameraTorch
192
-  }, () => {
193
-    RtcEngine.setCameraTorchOn(this.state.isCameraTorch)
194
-  })
195
-}
197
+  toggleCameraTorch = () => {
198
+    this.setState({
199
+      isCameraTorch: !this.state.isCameraTorch
200
+    }, () => {
201
+      RtcEngine.setCameraTorchOn(this.state.isCameraTorch)
202
+    })
203
+  }
196 204
 
197
-toggleVideo = () => {
198
-  this.setState({
199
-    disableVideo: !this.state.videodisableVideo
200
-  }, () => {
201
-    this.state.disableVideo ? RtcEngine.enableVideo() : RtcEngine.disableVideo()
202
-  });
203
-}
205
+  toggleVideo = () => {
206
+    this.setState({
207
+      disableVideo: !this.state.videodisableVideo
208
+    }, () => {
209
+      this.state.disableVideo ? RtcEngine.enableVideo() : RtcEngine.disableVideo()
210
+    });
211
+  }
204 212
 
205
-toggleHideButtons = () => {
206
-  this.setState({
207
-    hideButton: !this.state.hideButton
208
-  })
209
-}
213
+  toggleHideButtons = () => {
214
+    this.setState({
215
+      hideButton: !this.state.hideButton
216
+    })
217
+  }
210 218
 
211
-onPressVideo = (uid) => {
212
-  this.setState({
213
-    selectedUid: uid
214
-  }, () => {
219
+  onPressVideo = (uid) => {
215 220
     this.setState({
216
-      visible: true
221
+      selectedUid: uid
222
+    }, () => {
223
+      this.setState({
224
+        visible: true
225
+      })
217 226
     })
218
-  })
219
-}
227
+  }
220 228
 
221
-buttonsView = ({hideButton, isCameraTorch, disableVideo, isMute, isSpeaker}) => {
222
-  if (!hideButton) {
223
-  return (
224
-    <View>
225
-      <OperateButton
226
-        style={{alignSelf: 'center', marginBottom: -10}}
227
-        onPress={this.handleCancel}
228
-        imgStyle={{width: 60, height: 60}}
229
-        source={BtnEndCall()}
230
-    />
231
-    <View style={styles.bottomView}>
232
-      <OperateButton
233
-        onPress={this.toggleCameraTorch}
234
-        imgStyle={{width: 40, height: 40}}
235
-        source={isCameraTorch ? EnablePhotoflash() : DisablePhotoflash()}
236
-      />
237
-      <OperateButton
238
-        onPress={this.toggleVideo}
239
-        source={disableVideo ? EnableCamera() : DisableCamera()}
240
-      />
241
-    </View>
242
-    <View style={styles.bottomView}>
243
-      <OperateButton
244
-        onPress={this.toggleAllRemoteAudioStreams}
245
-        source={isMute ? IconMuted() : BtnMute()}
246
-      />
247
-      <OperateButton
248
-        onPress={this.switchCamera}
249
-        source={BtnSwitchCamera()}
250
-      />
251
-      <OperateButton
252
-        onPress={this.toggleSpeakerPhone}
253
-        source={!isSpeaker ? IconSpeaker() : BtnSpeaker()}
229
+  buttonsView = ({hideButton, isCameraTorch, disableVideo, isMute, isSpeaker}) => {
230
+    if (!hideButton) {
231
+    return (
232
+      <View>
233
+        <OperateButton
234
+          style={{alignSelf: 'center', marginBottom: -10}}
235
+          onPress={this.handleCancel}
236
+          imgStyle={{width: 60, height: 60}}
237
+          source={BtnEndCall()}
254 238
       />
255
-    </View>
256
-    </View>)
239
+      <View style={styles.bottomView}>
240
+        <OperateButton
241
+          onPress={this.toggleCameraTorch}
242
+          imgStyle={{width: 40, height: 40}}
243
+          source={isCameraTorch ? EnablePhotoflash() : DisablePhotoflash()}
244
+        />
245
+        <OperateButton
246
+          onPress={this.toggleVideo}
247
+          source={disableVideo ? EnableCamera() : DisableCamera()}
248
+        />
249
+      </View>
250
+      <View style={styles.bottomView}>
251
+        <OperateButton
252
+          onPress={this.toggleAllRemoteAudioStreams}
253
+          source={isMute ? IconMuted() : BtnMute()}
254
+        />
255
+        <OperateButton
256
+          onPress={this.switchCamera}
257
+          source={BtnSwitchCamera()}
258
+        />
259
+        <OperateButton
260
+          onPress={this.toggleSpeakerPhone}
261
+          source={!isSpeaker ? IconSpeaker() : BtnSpeaker()}
262
+        />
263
+      </View>
264
+      </View>)
265
+    }
257 266
   }
258
-}
259
-
260
-agoraPeerViews = ({visible, peerIds}) => {
261
-  return (visible ? 
262
-  <View style={styles.videoView} /> :
263
-  <View style={styles.videoView}>{
264
-    peerIds.map((uid, key) => (
265
-    <TouchableOpacity
266
-      activeOpacity={1}
267
-      onPress={() => this.onPressVideo(uid)}
268
-      key={key}>
269
-    <AgoraView
270
-        style={styles.remoteView}
271
-        zOrderMediaOverlay={true}
272
-        remoteUid={uid}
273
-    />
274
-    </TouchableOpacity>
275
-    ))
276
-    }</View>)
277
-}
278 267
 
279
-modalView = ({visible}) => {
280
-  return (
281
-  <Modal
282
-    visible={visible}
283
-    presentationStyle={'fullScreen'}
284
-    animationType={'slide'}
285
-    onRequestClose={() => {}}
286
-    >
287
-    <TouchableOpacity
288
-      activeOpacity={1}
289
-      style={{flex: 1}}
290
-      onPress={() => this.setState({
291
-        visible: false
292
-    })} >
268
+  agoraPeerViews = ({visible, peerIds}) => {
269
+    return (visible ? 
270
+    <View style={styles.videoView} /> :
271
+    <View style={styles.videoView}>{
272
+      peerIds.map((uid, key) => (
273
+      <TouchableOpacity
274
+        activeOpacity={1}
275
+        onPress={() => this.onPressVideo(uid)}
276
+        key={key}>
293 277
       <AgoraView
294
-        style={{flex: 1}}
295
-        zOrderMediaOverlay={true}
296
-        remoteUid={this.state.selectedUid}
278
+          style={styles.remoteView}
279
+          zOrderMediaOverlay={true}
280
+          remoteUid={uid}
297 281
       />
298
-    </TouchableOpacity>
299
-  </Modal>)
300
-}
282
+      </TouchableOpacity>
283
+      ))
284
+      }</View>)
285
+  }
301 286
 
302
-render () {
303
-  if (!this.state.joinSucceed) {
287
+  modalView = ({visible}) => {
304 288
     return (
305
-    <View style={{flex: 1, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center'}}>
306
-      <Text>Creating a video conference...</Text>
307
-    </View>
308
-    )
289
+    <Modal
290
+      visible={visible}
291
+      presentationStyle={'fullScreen'}
292
+      animationType={'slide'}
293
+      onRequestClose={() => {}}
294
+      >
295
+      <TouchableOpacity
296
+        activeOpacity={1}
297
+        style={{flex: 1}}
298
+        onPress={() => this.setState({
299
+          visible: false
300
+      })} >
301
+        <AgoraView
302
+          style={{flex: 1}}
303
+          zOrderMediaOverlay={true}
304
+          remoteUid={this.state.selectedUid}
305
+        />
306
+      </TouchableOpacity>
307
+    </Modal>)
309 308
   }
310 309
 
311
-  return (
312
-    <TouchableOpacity
313
-      activeOpacity={1}
314
-      onPress={this.toggleHideButtons}
315
-      style={styles.container}
316
-    >
317
-      <AgoraView style={styles.localView} showLocalVideo={true} />
318
-        <View style={styles.absView}>
319
-          {this.agoraPeerViews(this.state)}
320
-          {this.buttonsView(this.state)}
321
-        </View>
322
-      {this.modalView(this.state)}
323
-    </TouchableOpacity>
310
+  render () {
311
+    if (!this.state.joinSucceed) {
312
+      return (
313
+      <View style={{flex: 1, backgroundColor: '#fff', justifyContent: 'center', alignItems: 'center'}}>
314
+        <Text>Creating a video conference...</Text>
315
+      </View>
316
+      )
317
+    }
318
+
319
+    return (
320
+      <TouchableOpacity
321
+        activeOpacity={1}
322
+        onPress={this.toggleHideButtons}
323
+        style={styles.container}
324
+      >
325
+        <AgoraView style={styles.localView} showLocalVideo={true} />
326
+          <View style={styles.absView}>
327
+            <Text>channelName: {this.props.channelName}, peers: {this.state.peerIds.length}</Text>
328
+            {this.agoraPeerViews(this.state)}
329
+            {this.buttonsView(this.state)}
330
+          </View>
331
+        {this.modalView(this.state)}
332
+      </TouchableOpacity>
324 333
     )
325
-  } 
326
-}
334
+  }
335
+}

+ 2
- 0
samples/simpleDemo/package.json View File

@@ -6,6 +6,8 @@
6 6
     "start": "node node_modules/react-native/local-cli/cli.js start",
7 7
     "ios": "react-native run-ios && react-native log-ios",
8 8
     "android": "react-native run-android && react-native log-android",
9
+-   "bundle-android": "react-native bundle --entry-file index.js --bundle-output android/app/build/generated/assets/react/release/index.android.bundle --platform android --assets-dest android/app/src/main/res --dev false",
10
+-   "build-android": "cd android && ./gradlew assembleRelease",
9 11
     "test": "jest"
10 12
   },
11 13
   "dependencies": {

+ 26
- 1
samples/simpleDemo/utils.js View File

@@ -1 +1,26 @@
1
-export const APPID = 'Your Agora APP_ID'; //'Your Agora APP_ID'
1
+export const APPID = 'Your Agora APP_ID'; //'Your Agora APP_ID'
2
+// iPhoneX Xs
3
+const X_WIDTH = 375;
4
+const X_HEIGHT = 812;
5
+
6
+// iPhoneXR XsMax
7
+const XR_WIDTH = 414;
8
+const XR_HEIGHT = 896;
9
+
10
+//判断是否为iphoneX或Xs
11
+export function isIphoneX(Platform, SCREEN_WIDTH, SCREEN_HEIGHT) {
12
+    return (
13
+        Platform.OS === 'ios' &&
14
+        ((SCREEN_HEIGHT === X_HEIGHT && SCREEN_WIDTH === X_WIDTH) ||
15
+        (SCREEN_HEIGHT === X_WIDTH && SCREEN_WIDTH === X_HEIGHT))
16
+    )
17
+};
18
+
19
+//判断是否为iphoneXR或XsMAX
20
+export function isIphoneXR(Platform, SCREEN_WIDTH, SCREEN_HEIGHT) {
21
+    return (
22
+        Platform.OS === 'ios' &&
23
+        ((SCREEN_HEIGHT === XR_HEIGHT && SCREEN_WIDTH === XR_WIDTH) ||
24
+        (SCREEN_HEIGHT === XR_WIDTH && SCREEN_WIDTH === XR_HEIGHT))
25
+    )
26
+};