Native API 之 CameraRollManager

2017-06-04  本文已影响35人  卑鄙的鹿尤菌

CameraRollManager提供了JS与设备相册进行交互的相关功能,它包括两个API:

具体实现分析如下。


saveToCameraRoll

saveToCameraRoll方法启动了一个后台异步任务来完成图片的存储工作:

    protected void doInBackgroundGuarded(Void... params) {
      File source = new File(mUri.getPath()); // 待存储图片文件
      FileChannel input = null, output = null;
      try {
        // SD卡目录
        File exportDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
        exportDir.mkdirs();
        if (!exportDir.isDirectory()) { //没权限
          mPromise.reject(ERROR_UNABLE_TO_LOAD, "External media storage directory not available");
          return;
        }
        File dest = new File(exportDir, source.getName());
        int n = 0;
        // 避免重名覆盖
        String fullSourceName = source.getName();
        String sourceName, sourceExt;
        if (fullSourceName.indexOf('.') >= 0) {
          sourceName = fullSourceName.substring(0, fullSourceName.lastIndexOf('.'));
          sourceExt = fullSourceName.substring(fullSourceName.lastIndexOf('.'));
        } else {
          sourceName = fullSourceName;
          sourceExt = "";
        }
        while (!dest.createNewFile()) {
          dest = new File(exportDir, sourceName + "_" + (n++) + sourceExt);
        }
        // 开始文件复制操作
        input = new FileInputStream(source).getChannel();
        output = new FileOutputStream(dest).getChannel();
        output.transferFrom(input, 0, input.size());
        input.close();
        output.close();
        // 发起扫描
        MediaScannerConnection.scanFile(
            mContext,
            new String[]{dest.getAbsolutePath()},
            null,
            new MediaScannerConnection.OnScanCompletedListener() {
              @Override
              public void onScanCompleted(String path, Uri uri) {
                if (uri != null) {
                  mPromise.resolve(uri.toString());
                } else {
                  mPromise.reject(ERROR_UNABLE_TO_SAVE, "Could not add image to gallery");
                }
              }
            });
      } catch (IOException e) {
        mPromise.reject(e);
      } finally {
        if (input != null && input.isOpen()) {
          try {
            input.close();
          } catch (IOException e) {
            FLog.e(ReactConstants.TAG, "Could not close input channel", e);
          }
        }
        if (output != null && output.isOpen()) {
          try {
            output.close();
          } catch (IOException e) {
            FLog.e(ReactConstants.TAG, "Could not close output channel", e);
          }
        }
      }
    }

public void getPhotos(final ReadableMap params, final Promise promise)

{
    "first": int,返回的图片个数
     "after": String 上一次调用所返回的cursor
    "groupName":String 相册名称
    "mimeType":Array //指定要返回的图片类型
}
{
    "page_info": { //本页搜索信息
        "end_cursor": "1496373800000", 
        "has_next_page": true
    }, 
    "edges": [// 本次搜索所获取的图片信息, 每个node表示一张图片
        {
            "node": { 
                "timestamp": 1496384866, 
                "group_name": "splash", // 相册名称
                "type": "image/jpeg", 
                "image": {
                    "height": 1920, 
                    "width": 1080, 
                    "uri": "content://media/external/images/media/7217"
                }
            }
        }, 
        {
            "node": {
                "timestamp": 1496373800, 
                "group_name": "a", 
                "type": "image/png", 
                "image": {
                    "height": 64, 
                    "width": 96, 
                    "uri": "content://media/external/images/media/7218"
                }
            }
        }
    ]
}

getPhotos 在启动了一个后台异步任务使用系统提供的ContentResolver从SD卡中获取指定的图片。

protected void doInBackgroundGuarded(Void... params) {
      StringBuilder selection = new StringBuilder("1");
      List<String> selectionArgs = new ArrayList<>();
      if (!TextUtils.isEmpty(mAfter)) {
        selection.append(" AND " + SELECTION_DATE_TAKEN);
        selectionArgs.add(mAfter);
      }
      if (!TextUtils.isEmpty(mGroupName)) {
        selection.append(" AND " + SELECTION_BUCKET);
        selectionArgs.add(mGroupName);
      }
      if (mMimeTypes != null && mMimeTypes.size() > 0) {
        selection.append(" AND " + Images.Media.MIME_TYPE + " IN (");
        for (int i = 0; i < mMimeTypes.size(); i++) {
          selection.append("?,");
          selectionArgs.add(mMimeTypes.getString(i));
        }
        selection.replace(selection.length() - 1, selection.length(), ")");
      }
      WritableMap response = new WritableNativeMap();
      ContentResolver resolver = mContext.getContentResolver();

      try {
        Cursor photos = resolver.query(
            Images.Media.EXTERNAL_CONTENT_URI,
            PROJECTION,
            selection.toString(),
            selectionArgs.toArray(new String[selectionArgs.size()]),
            Images.Media.DATE_TAKEN + " DESC, " + Images.Media.DATE_MODIFIED + " DESC LIMIT " +
                (mFirst + 1)); // set LIMIT to first + 1 so that we know how to populate page_info
        if (photos == null) {
          mPromise.reject(ERROR_UNABLE_TO_LOAD, "Could not get photos");
        } else {
          try {
            putEdges(resolver, photos, response, mFirst);
            putPageInfo(photos, response, mFirst);
          } finally {
            photos.close();
            mPromise.resolve(response);
          }
        }
      } catch (SecurityException e) {
        mPromise.reject(
            ERROR_UNABLE_TO_LOAD_PERMISSION,
            "Could not get photos: need READ_EXTERNAL_STORAGE permission",
            e);
      }
    }

在JS端,ReactNative将CameraRollManager封装为CameraRoll.js,加入了一些入参和回参的检查。

上一篇 下一篇

猜你喜欢

热点阅读