React Native 使用react-native-image-picker外掛上傳圖片詳細步驟
專案需要用到上傳圖片功能,經過一番折騰勉強完成需求,整理一下做個記錄。外掛選擇是react-native-image-picker,還挺好用的,不過需要分ios和android不同平臺去配置.http://www.jianshu.com/p/8dd405dbd663
IOS:
1.在Xcode右擊專案選擇Add Files to 'XXX',(這裡的xxx就是你的專案).然後找到專案的node_modules ➜ react-native-image-picker ➜ ios ➜ select RNImagePicker.xcodeproj新增進去。
2.在Build Phases的Link Binary With Libraries中新增RNImagePicker.a
Android:
1.在android/settings.gradle檔案中新增如下程式碼
include ':react-native-image-picker'
project(':react-native-image-picker').projectDir = new File(settingsDir, '../node_modules/react-native-image-picker/android')
2.在android/app/build.gradle檔案的dependencies中新增如下程式碼:
compile project(':react-native-image-picker' )
3.在AndroidManifest.xml檔案中新增
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
4.最後在MainApplication.java檔案中新增如下程式碼:其中new程式碼加到new MainReactPackage()所在位置。
import com.imagepicker.ImagePickerPackage;
new ImagePickerPackage()
以上就配置好了,ios如果是10+的系統還需另外增加配置,這裡就不說了。因為專案中用到這個功能的地方不止一處,所以就封裝成一個外掛了,名為CameraButton.js。程式碼如下(去掉了一些實際專案中的邏輯,可能看起來有點怪)
import React from 'react'
import {
TouchableOpacity,
StyleSheet,
Platform,
ActivityIndicator,
View,
Text,
ToastAndroid
} from 'react-native'
var ImagePicker = require('react-native-image-picker');
import Icon from 'react-native-vector-icons/Ionicons';
const options = {
title: '選擇圖片',
cancelButtonTitle: '取消',
takePhotoButtonTitle: '拍照',
chooseFromLibraryButtonTitle: '圖片庫',
cameraType: 'back',
mediaType: 'photo',
videoQuality: 'high',
durationLimit: 10,
maxWidth: 600,
maxHeight: 600,
aspectX: 2,
aspectY: 1,
quality: 0.8,
angle: 0,
allowsEditing: false,
noData: false,
storageOptions: {
skipBackup: true,
path: 'images'
}
};
class CameraButton extends React.Component {
constructor(props){
super(props);
this.state = {
loading:false
}
}
render() {
const {photos,type} = this.props;
let conText;
if(photos.length > 0){
conText = (<View style={styles.countBox}>
<Text style={styles.count}>{photos.length}</Text>
</View>);
}
return (
<TouchableOpacity
onPress={this.showImagePicker.bind(this)}
style={[this.props.style,styles.cameraBtn]}>
<View>
<Icon name="md-camera" color="#aaa" size={34}/>
{conText}
</View>
</TouchableOpacity>
)
}
showImagePicker() {
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;
if (Platform.OS === 'android') {
source = {uri: response.uri, isStatic: true}
} else {
source = {uri: response.uri.replace('file://', ''), isStatic: true}
}
let file;
if(Platform.OS === 'android'){
file = response.uri
}else {
file = response.uri.replace('file://', '')
}
this.setState({
loading:true
});
this.props.onFileUpload(file,response.fileName||'未命名檔案.jpg')
.then(result=>{
this.setState({
loading:false
})
})
}
});
}
}
const styles = StyleSheet.create({
cameraBtn: {
padding:5
},
count:{
color:'#fff',
fontSize:12
},
fullBtn:{
justifyContent:'center',
alignItems:'center',
backgroundColor:'#fff'
},
countBox:{
position:'absolute',
right:-5,
top:-5,
alignItems:'center',
backgroundColor:'#34A853',
width:16,
height:16,
borderRadius:8,
justifyContent:'center'
}
});
export default CameraButton;
然後在需要用到的地方引入
import CameraButton from '../../component/huar/cameraButton'
View稱程式碼:(簡潔)
<CameraButton style={styles.cameraBtn}
photos={[]}
onFileUpload={this.onFileUpload} />
點選事件:
onFileUpload(file, fileName){
return this.props.uploadAvatar({
id: this.props.user.ID,
type:'logo',
obj:'user',
corpId: this.props.cropId
}, file, fileName)}
Action請求程式碼:
function actions(dispatch) {
return {
fileUrl,fileName)=>dispatch(Actions.uploadAvatar(params, fileUrl,fileName))
}
}
上面已經獲取到資料,接下來就是上傳了。(uploadAvatar中第一個物件是專案上傳需要用到的引數)
actions中的uploadAvatar函式如下
function uploadAvatar(params, fileUrl, fileName) {
return dispatch=> {
return UserService.uploadImage(params, fileUrl, fileName)
.then(result=> {
dispatch({
type: UPDATE_AVATAR,
path: result.path
})
return result
})
}
}
UserService.uploadImage的程式碼如下
export function uploadImage(params, fileUrl,fileName) {
return http.uploadFile(`${config.UploadImage}`, params, fileUrl,fileName)
}
$中是上傳的地址.我們用的是FontDate上傳,在http中的uploadFile函式程式碼如下:
let queryString = require('query-string');
import Storage from './storage'
import {
Platform
} from 'react-native'
const os = Platform.OS;
async function uploadFile(url, params, fileUrl,fileName) {
let Access_Token = await Storage.getItem('Access_Token');
let data = new FormData();
data.append('file', {
uri: fileUrl,
name: fileName,
type: 'image/jpeg'
});
Object.keys(params).forEach((key)=> {
if (params[key] instanceof Date) {
data.append(key, value.toISOString())
} else {
data.append(key, String(params[key]))
}
});
const fetchOptions = {
method: 'POST',
headers: {
'Accept': 'application/json',
'Access_Token': Access_Token ? Access_Token : '',
'UserAgent':os
},
body: data
};
return fetch(url, fetchOptions)
.then(checkStatus)
.then(parseJSON)
}
因為上傳需要判斷token 所以用了async/await。