ReactNative: 了解CameraRoll的API使用


一、簡介

在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);
View Code

   

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靜態庫嵌入到項目中。好了,再運行就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM