React Native SDK for OSS

此文主要介绍 React Native SDK for OSS的方方面面,包括相关基本概念、项目背景、项目方案、环境搭建运行、使用姿势、注意事项等。文末的附件可运行Example Zip压缩包和针对新手的入门实用文章《从0开始搭建React Native for OSS项目》。

背景

OSS支持React Native SDK,主要有以下几个原因。

  • React Native跨平台开发技术目前在移动开发领域仍然是一个非常热门的技术,在国内外互联网公司中都有广泛使用,比如:Facebook、微软、Airbnb、百度、腾讯、京东、爱奇艺等科技公司。此外从我们的ali-oss-js-sdk上的issue上也可以看到,从2015年底到现在有接近10个issue是关于支持react native平台的。近日我们把这些issue合并成一个并统一支持,旨在希望能够更好的服务于使用React Native开发移动应用的客户,同时准备把项目开源出去从而聆听更多客户的声音,也可以让更多的开发者加入我们,持续改善OSS服务。
  • AWS在9个月前正式支持React Native平台,最近AWS也专门开发了aws-amplify-react-native包用于支持React Native平台。近期关注React Native官网的人会发现,其Blog专栏里专门写了一边文章《Using AWS with React Native》,由此可以看出AWS对于支持React Native平台的重视,此外国内的七牛云也单独开发了用于支持react-native的SDK包,因此阿里云OSS有必要去支持React Native平台。
  • 通过github和npm包仓库调查,其实部分开发者已经针对自身业务场景需求或多或少地在React native平台上支持某一个API,但都不够全面,而且缺乏长期维护的动力,不能服务于更多的开发者。因此我们决定统一开发来支持react native平台,为更多的开发者提供标杆,也可以让更多有需求的开发者参与加入。

什么是React Native

React Native是facebook团队于2015年推出的移动端跨平台解决方案,它主张的理念是learn once ,run anywhere。React Native本质上和React是两个不同的东西。React Native旨在让移动开发者通过简捷的前端语法写出Native级别的性能体验,其页面性能介于H5和原生页面之间,而且更加接近原生页面,完美兼顾性能与动态性,因此受到很多移动开发者的青睐,很多团队也基于此造就符合自身业务需求的*。

React Native无论是在Andoird、iOS还是浏览器都需要一个JS的运行环境, 在iOS上直接使用内置的javascriptcore,实现JS与OC的通信,最终渲染成原生的iOS页面。 在Android 通过JNI调用C++代码通过javascriptcore来执行JS,实现JS与JAVA的通信,最终渲染成原生安卓页面。 此外react-native还集成了安卓或者iOS其他开源组件库,具体的原理细节读者可参考文档末尾贴出的链接,React Native的整个架构图如下。

React Native SDK for OSS

React Native SDK for OSS方案

从React Native的学习调研、环境搭建到OSS支持React Native平台到代码文档编写完成,整个过程持续一周多,目前项目正在申请走开源流程,可查看项目ali-oss-rn-sdk仓库。中间方案经历一次变革。目前整体开发方案采用方案二。

方案一

从nodejs、browserjs的角度通过不断替换包、新增包的方式转换成React Native平台需要的RN.js, 早期调研经过排查定位到具体的包和不兼容的代码,列出部分如下:

1.  xml2js  => react-native-xml2js 
2. client中createRequest mimie.lookup == > getType
3. stream =>stream-browserify 
4. http => stream-http 
5. https=>https-browserfiy 
6. shim/xhr.js  constants =>constants-browserify  
7. assert代码块注释lib/bucket.js
8. Bufffer: shims/xhr.js  libclient.js  common/signUtils
9. timer模块等等

缺点
经过大量调试解决了包依赖和不兼容报错,但是需要改动大量的已有包和代码。通过这种方式生产的RN包,对于JS开发者来说完全是黑盒,改造后的JS也不一定是React Native平台真正需要的JS,同时对于React Native平台对应的Native(Android、IOS)端执行的逻辑完全搞不清楚。就算生成RN需要包,还是需要在Native(Android和IOS)端执行。

方案二

从安卓SDK和IOS SDK角度出发,在已有SDK的基础上,通过React Native插件的方式,再封装一个React Native的包,底层调用Native(Android、IOS) API,上层通过React Native插件的方式暴漏JS API,以npm包的形式发出,这种方式可行更高,更靠谱,思路更清晰。目前所有代码都是基于这种方式开发。

针对方案二我们以具体的asyncUpload接口为例来阐述如何实现兼容安卓、iOS的API,安卓和iOS端需要统一暴漏Native模块RNAliyunOSS供JS调用。

安卓

安卓端需要新建RNAliyunOssModule类继承ReactContextBaseJavaModule,同时重写getName方法,getName的返回值为'RNAliyunOSS',这个就是安卓暴漏给JS的模块名,如果需要安卓暴漏方法给JS需要在暴漏的方法前加上注解@ReactMethod,可参考下面代码,具体代码可以参考官方代码

public class RNAliyunOssModule extends ReactContextBaseJavaModule {
    private OSS mOSS;

    public RNAliyunOssModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    //返回给JS调用的模块名
    @Override
    public String getName() {
        return "RNAliyunOSS";
    }
    //返回给JS模块调用的方法
    @ReactMethod
    public void initWithServerSTS(final String server, String endPoint, ReadableMap configuration) {
        /<strong>这里写调用安卓代码授权的逻辑</strong>/
    }
    @ReactMethod
    public void asyncUpload(String bucketName, String ossFile, String sourceFile,ReadableMap options, final Promise promise) {
        /**这里写调用安卓代码上传的逻辑*/
    }
}

此外RNAliyunOssModule也需要在MainApplication.java中进行注册

public class MainApplication extends Application implements ReactApplication {
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new RNAliyunOssPackage()
      );
    }
  /*<strong>各种代码</strong>*/
}

iOS

新建文件RNAliyunOSS.m和RNAliyunOSS.h文件,RNAliyunOSS.m文件里通过RCT_EXPORT_MODULE()模块名给JS,通过 RCT_REMAP_METHOD暴漏方法名给JS,可参考如下代码:RNAliyunOSS.m

#import "RNAliyunOSS.h"
#import <React/RCTLog.h>
#import <React/RCTConvert.h>

@implementation RNAliyunOSS

RCT_REMAP_METHOD(asyncUpload, asyncUploadWithBucketName:(NSString *)bucketName objectKey:(NSString *)objectKey filepath:(NSString *)filepath options:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){
    /**oc native code*/
}
RCT_EXPORT_MODULE()

@end

JS

JS端只需引入react-native NativeModules模块就可引用上述安卓和iOS端暴漏的RNAliyunOSS模块和上面的方法asyncUpload,参考代码如下

import {DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform} from "react-native";
const {RNAliyunOSS} = NativeModules;
export default AliyunOSS = {
    initWithServerSTS(server, endPoint, configuration = conf) {
        RNAliyunOSS.initWithServerSTS(server, endPoint, configuration);
    },  
    /**
     * Asynchronously uploading
     */
    asyncUpload(bucketName, objectKey, filepath,options) {
        return RNAliyunOSS.asyncUpload(bucketName, objectKey, filepath,options);
    }
};

React Native SDK for OSS的使用姿势

  • 导入aliyun-oss-rn-sdk包
import AliyunOSS from 'aliyun-oss-rn-sdk'
  • 初始化授权

目前提供四种方式,包括initWithPlainTextAccessKey、initWithImplementedSigner、initWithSecurityToken、initWithServerSTS建议initWithServerSTS, 其中server为本地鉴权服务器。

  • 调用API,以upload接口为例,并监听上传事件
    console.log(res)
}).catch((error) => {
   console.log(error)
})

//监听上传事件
 const uploadProgress = p => console.log(p.currentSize / p.totalSize);
 AliyunOSS.addEventListener('uploadProgress', uploadProgress);

如何运行附件Example工程

  1. 开启鉴权server,可以参考ali-oss-rn-sdk项目下的script文件,修改config.json里的accessKeyId、accessKeySecret和RoleArn,然后运行node index.js默认开启9000端口 2.项目下运行npm install,然后运行react-native link
  2. 打开项目下的app.js,在initWithServerSTS函数中修改server地址为本地鉴权server地址
  3. 打开项目目录运行 npm run start
  4. android studio打开android文件下的安卓项目编译运行或者运行react-native run-android命令,成功运行后可看到界面
    React Native SDK for OSS
  5. 使用xcode打开ios文件夹下的iOS项目编译运行或者运行react-native run-ios 命令,成功运行后可看到界面
    React Native SDK for OSS

Reference

上一篇:Linux initrd 学习笔记


下一篇:OSS直传与UXCore-Uploader实践