一、簡介
在APP中照相機的使用非常普遍,需要的相機的功能可能是拍攝圖片、保存圖片、獲取圖片、拍攝視頻、獲取視頻、掃描二維碼等等。在ReactNative中,提供了一個API來實現這些功能,也即CameraRoll。注意,為了訪問運行iOS 10或更高版本的設備上的“相機膠卷”,需要用戶的許可。 用描述您的應用如何使用此數據的字符串應添加“ Info.plist”中的“ NSCameraUsageDescription”鍵。
二、API
這個CameraRoll提供了對照相機控制的權限,它提供了常用的靜態屬性和方法,使用簡單。具體的API解釋如下所示:
屬性:
//組類型選項,是一個數組 static GroupTypesOptions: Array<string> //也即: //Album:專輯 All:所有 Event:事件 //Faces:面孔 Library:圖庫 PhotoStream:照片流 SavedPhotos:保存的圖片 var GROUP_TYPES_OPTIONS = [ 'Album', 'All', 'Event', 'Faces', 'Library', 'PhotoStream', 'SavedPhotos', // default ]; //資源類型選項,是一個數組 static AssetTypeOptions: Array<string> //也即:All:所有 Videos:視頻 Photos:照片 var ASSET_TYPE_OPTIONS = [ 'All', 'Videos', 'Photos', // default ];
方法:
保存資源
//保存圖片到相冊 static saveImageWithTag(tag: string): Promise<Object>{} //保存資源 static saveToCameraRoll(tag: string, type?: 'photo' | 'video'): Promise<Object> {} //返回值解釋 Promise:這是一個異步處理,它是一個函數,包裹着當前操作的邏輯,是否保存成功。 //注意如下: 1、將照片或視頻保存到相機膠卷/圖庫。 2、在iOS上,tag標簽可以是任何圖像URI(包括本地,遠程資產庫和base64數據URI)或本地視頻文件URI(目前不支持遠程或數據URI用於保存視頻)。在Android上,tag標簽必須是本地圖像或視頻URI,例如““ file:///sdcard/img.png”`。 3、如果標簽的文件擴展名為.mov或.mp4,則將其推斷為視頻。 否則,它將被視為照片。 要覆蓋自動選擇,您可以傳遞一個可選的“ type”參數,該參數必須是“ photo”或“ video”之一。 4、第1個方法已過時,被官方棄用了。推薦用方法2。
獲取資源
//獲取資源 static getPhotos(params){ .......... if(獲取到了){ ..........將結果設置到回調函數中......... RCTCameraRollManager.getPhotos(params).then(successCallback, errorCallback); } return RCTCameraRollManager.getPhotos(params); } //params為參數,它有對應的格式要求,系統使用getPhotosParamChecker檢查,格式如下: var getPhotosParamChecker = createStrictShapeTypeChecker({ //所需的照片數量與照片應用程序的順序相反(即,“保存的照片”中最新的照片)。 first: PropTypes.number.isRequired, //與上次調用getPhotos返回的,與page_info {end_cursor}相匹配的游標 after: PropTypes.string, //指定要將結果過濾到的組類型。 groupTypes: PropTypes.oneOf(GROUP_TYPES_OPTIONS), //為組名稱指定過濾器,例如“最近的照片”或自定義相冊標題。 groupName: PropTypes.string, //指定資源類型過濾器 assetType: PropTypes.oneOf(ASSET_TYPE_OPTIONS), //按mimetype(例如image/jpeg)過濾。 mimeTypes: PropTypes.arrayOf(PropTypes.string), }); //這個函數的返回值也是特定的格式,系統使用getPhotosParamChecker檢查,格式如下: var getPhotosReturnChecker = createStrictShapeTypeChecker({ // $FlowFixMe(>=0.41.0) edges: PropTypes.arrayOf(createStrictShapeTypeChecker({ node: createStrictShapeTypeChecker({ type: PropTypes.string.isRequired, group_name: PropTypes.string.isRequired, image: createStrictShapeTypeChecker({ uri: PropTypes.string.isRequired, height: PropTypes.number.isRequired, width: PropTypes.number.isRequired, isStored: PropTypes.bool, }).isRequired, timestamp: PropTypes.number.isRequired, location: createStrictShapeTypeChecker({ latitude: PropTypes.number, longitude: PropTypes.number, altitude: PropTypes.number, heading: PropTypes.number, speed: PropTypes.number, }), }).isRequired, })).isRequired, page_info: createStrictShapeTypeChecker({ has_next_page: PropTypes.bool.isRequired, start_cursor: PropTypes.string, end_cursor: PropTypes.string, }).isRequired, }); //也即返回的是一個Promise,在解析后將具有以下形狀: - `edges` : {Array<node>} An array of node objects - `node`: {object} An object with the following shape: - `type`: {string} - `group_name`: {string} - `image`: {object} : An object with the following shape: - `uri`: {string} - `height`: {number} - `width`: {number} - `isStored`: {boolean} - `timestamp`: {number} - `location`: {object} : An object with the following shape: - `latitude`: {number} - `longitude`: {number} - `altitude`: {number} - `heading`: {number} - `speed`: {number} - `page_info` : {object} : An object with the following shape: - `has_next_page`: {boolean} - `start_cursor`: {boolean} - `end_cursor`: {boolean}
三、使用
myCameraRollView.js
import React, { Component } from 'react'; import { StyleSheet, View, Image, Text, TouchableOpacity, Dimensions, CameraRoll } from 'react-native'; const imageURL = 'http://a3.att.hudong.com/35/34/19300001295750130986345801104.jpg'; const {width} = Dimensions.get('window'); export default class MyCameraRollView extends Component{ state = { uri: "" }; //保存圖片 saveImage() { //方式一 let promise = CameraRoll.saveToCameraRoll(imageURL, 'photo'); promise.then(function (result) { alert('保存成功!地址如下:\n' + result); }).catch(function (error) { alert('保存失敗!\n' + error); }); //方式二 // CameraRoll.saveToCameraRoll(imageURL, 'photo').then(result => { // alert('保存成功!地址如下:\n' + result); // }).catch(error => { // alert('保存失敗!\n' + error); // }) } //獲取圖片 getAndShowImage(){ const params = { //照片數量 first: 1, //組類型 groupTypes: 'All', //資源類型 assetType: 'Photos', //資源格式 mimeTypes: ['image/jpeg'], }; CameraRoll.getPhotos(params).then( (response) => { const edges = response.edges; edges.map( (edge) => { this.setState({ uri: edge.node.image.uri }); console.log('uri:'+edge.node.image.uri); console.log('height:'+edge.node.image.height); console.log('width:'+edge.node.image.width); console.log('isStored:'+edge.node.image.isStored); }) }, (error) => { alert('獲取失敗!\n' + error); } ) } render() { const {uri,height,width} = this.state; return ( <View style={styles.container}> <View style={[styles.top,styles.center]}> <Image style={styles.image} resizeMode="stretch" source={uri?{uri: uri }:null}/> </View> <View style={styles.bottom}> <TouchableOpacity onPress={this.saveImage.bind(this)}> <Text style={styles.save}>保存圖片</Text> </TouchableOpacity> <TouchableOpacity onPress={this.getAndShowImage.bind(this)}> <Text style={styles.save}>獲取圖片並顯示</Text> </TouchableOpacity> </View> </View> ); } } const styles = StyleSheet.create({ container: { flex:1 }, top: { height: 300, marginTop: 20, marginLeft: 20, marginRight: 20, backgroundColor:'#4DE' }, image: { height: 300, width: width-40 }, bottom: { height: 100, marginTop: 100, marginLeft: 20, marginRight: 20 }, save: { fontSize: 25, textAlign:'center', marginTop: 20, borderWidth: 1, borderColor:'red' }, fetch: { fontSize: 25, textAlign:'center', marginTop: 20, borderWidth: 1, borderColor:'green' }, center: { justifyContent: 'center', alignItems: 'center' } });
index.ios.js

/** * Sample React Native App * https://github.com/facebook/react-native * @flow */ import React, { Component } from 'react'; import { AppRegistry, StyleSheet, View } from 'react-native'; import MyCameraRollView from "./src/MyCameraRollView"; export default class ReactNativeDemo extends Component { render() { return ( <View style={[styles.flex,styles.bgColor]}> <MyCameraRollView/> </View> ); } } const styles = StyleSheet.create({ flex: { flex: 1 }, bgColor: { backgroundColor: 'white' }, center: { alignItems: 'center', justifyContent: 'center', } }); AppRegistry.registerComponent('ReactNativeDemo', () => ReactNativeDemo);
2020-01-10 14:39:34.256 [info][tid:com.facebook.react.JavaScript] uri:assets-library://asset/asset.JPG?id=5C2769FB-E915-4A22-9100-7B02CAAB45A7&ext=JPG 2020-01-10 14:39:34.256 [info][tid:com.facebook.react.JavaScript] height:471 2020-01-10 14:39:34.257 [info][tid:com.facebook.react.JavaScript] width:670 2020-01-10 14:39:34.257 [info][tid:com.facebook.react.JavaScript] isStored:true
四、注意
1、iOS系統從iOS10開始,對於用戶隱私更加關注,因此對於相冊或者相機的使用,必須添加權限允許字段。字段分別是NSPhotoLibraryUsageDescription和NSPhotoLibraryAddUsageDescription。 info.plist的配置如圖所示:
2、如果在使用CameraRoll的API,然后運行項目時報錯(非對象錯誤),說明在xcode項目沒有導入需要的libRCTCameraRoll.a靜態庫。錯誤如下所示:
2020-01-10 10:50:42.462 [error][tid:com.facebook.react.JavaScript] undefined is not an object (evaluating 'RCTCameraRollManager.saveToCameraRoll') 2020-01-10 10:50:42.468 [fatal][tid:com.facebook.react.ExceptionsManagerQueue] Unhandled JS Exception: undefined is not an object (evaluating 'RCTCameraRollManager.saveToCameraRoll')
那么此時只需要把項目根路徑下的node_modules/react-native/Libraries/CameraRoll/RCTCameraRoll.xcodeproj導入xcode中的Libraries文件夾下即可。步驟如下:
第一步:打開xcode,選中Libraries文件夾,右鍵添加文件到該工程中
第二步:找到RCTCameraRoll.xcodeproj文件,添加到項目中,也即Add即可
第三步:添加完后,手動把libRCTCameraRoll.a靜態庫嵌入到項目中。好了,再運行就可以了。