You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何将Aspera SDK集成到React Native及Android端实现文件传输

React Native Android 集成 Aspera SDK 分步指南

我之前刚完成了React Native Android端集成Aspera SDK的文件传输需求,给你整理了一套亲测有效的分步指南,涵盖从准备到测试的全流程:

1. 前期准备

  • 先从IBM获取Aspera Mobile SDK for Android的资源包(通常是.aar格式的文件),还有官方提供的依赖清单、集成文档,这是基础前提
  • 确保你的React Native项目环境正常运行:Android SDK、NDK(如果SDK要求)都配置到位,RN版本建议用0.60+,因为autolinking能省不少配置功夫
  • 在RN项目的android/app/目录下新建libs文件夹,把下载好的Aspera .aar文件放进去

2. 配置Android项目

2.1 修改build.gradle依赖

打开android/app/build.gradle文件,做两处修改:

  • android块里添加本地仓库配置,让项目能识别libs里的aar文件:
repositories {
    flatDir {
        dirs 'libs'
    }
}
  • dependencies块里添加本地aar依赖,以及Aspera SDK要求的其他第三方依赖(比如okhttp、gson,具体看官方文档):
implementation files('libs/aspera-sdk-release.aar')
// 示例依赖,根据实际SDK要求调整版本
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.google.code.gson:gson:2.10.1'

2.2 配置Manifest权限

打开android/app/src/main/AndroidManifest.xml,添加文件传输必需的权限:

<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 文件读写权限(适配Android版本) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />

注意:如果Aspera SDK需要后台服务支持,记得按照官方文档在Manifest里注册对应的服务组件

3. 编写Native Module桥接原生SDK

React Native无法直接调用原生SDK,所以需要写一个Native Module做桥接:

3.1 创建Transfer模块类

android/app/src/main/java/com/你的项目包名/目录下新建AsperaFileTransferModule.java,封装上传、下载和进度回调:

package com.yourprojectpackage;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.ibm.aspera.sdk.transfer.TransferManager;
import com.ibm.aspera.sdk.transfer.TransferConfig;
import com.ibm.aspera.sdk.transfer.TransferCallback;

public class AsperaFileTransferModule extends ReactContextBaseJavaModule {
    private TransferManager transferManager;

    public AsperaFileTransferModule(ReactApplicationContext reactContext) {
        super(reactContext);
        // 根据Aspera服务器配置初始化TransferManager
        TransferConfig config = new TransferConfig.Builder()
                .setServerUrl("你的Aspera服务器地址")
                .setUsername("服务器账号")
                .setPassword("服务器密码")
                .build();
        transferManager = new TransferManager(config);
    }

    @Override
    public String getName() {
        return "AsperaFileTransfer"; // RN层调用的模块名
    }

    // 上传文件方法,暴露给RN
    @ReactMethod
    public void uploadFile(String localFilePath, String remotePath, Promise promise) {
        try {
            transferManager.upload(localFilePath, remotePath, new TransferCallback() {
                @Override
                public void onSuccess() {
                    promise.resolve("上传完成");
                }

                @Override
                public void onError(Exception e) {
                    promise.reject("UPLOAD_FAILED", e.getMessage());
                }

                @Override
                public void onProgress(long bytesTransferred, long totalBytes) {
                    // 发送进度事件到RN层
                    sendTransferProgressEvent((int) (bytesTransferred * 100 / totalBytes));
                }
            });
        } catch (Exception e) {
            promise.reject("UPLOAD_FAILED", e.getMessage());
        }
    }

    // 下载文件方法,暴露给RN
    @ReactMethod
    public void downloadFile(String remoteFilePath, String localSavePath, Promise promise) {
        try {
            transferManager.download(remoteFilePath, localSavePath, new TransferCallback() {
                @Override
                public void onSuccess() {
                    promise.resolve("下载完成");
                }

                @Override
                public void onError(Exception e) {
                    promise.reject("DOWNLOAD_FAILED", e.getMessage());
                }

                @Override
                public void onProgress(long bytesTransferred, long totalBytes) {
                    sendTransferProgressEvent((int) (bytesTransferred * 100 / totalBytes));
                }
            });
        } catch (Exception e) {
            promise.reject("DOWNLOAD_FAILED", e.getMessage());
        }
    }

    // 发送进度事件到RN的工具方法
    private void sendTransferProgressEvent(int progress) {
        getReactApplicationContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("TransferProgress", progress);
    }
}

3.2 创建Package注册模块

新建AsperaFileTransferPackage.java,用来注册刚才的Module:

package com.yourprojectpackage;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class AsperaFileTransferPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new AsperaFileTransferModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

注意:RN 0.60+版本支持autolinking,不需要手动注册Package;如果是旧版本,需要在MainApplication.javagetPackages()方法里添加packages.add(new AsperaFileTransferPackage());

4. React Native层封装与调用

4.1 创建工具类封装方法

在RN项目根目录新建AsperaTransfer.js,封装Native Module的方法和事件监听:

import { NativeModules, NativeEventEmitter } from 'react-native';

const { AsperaFileTransfer } = NativeModules;
const asperaEventEmitter = new NativeEventEmitter(AsperaFileTransfer);

// 监听传输进度
export const subscribeToProgress = (callback) => {
    return asperaEventEmitter.addListener('TransferProgress', (progress) => {
        callback(progress);
    });
};

// 上传文件
export const uploadFile = async (localPath, remotePath) => {
    try {
        const result = await AsperaFileTransfer.uploadFile(localPath, remotePath);
        return result;
    } catch (error) {
        throw new Error(`上传失败:${error.message}`);
    }
};

// 下载文件
export const downloadFile = async (remotePath, localSavePath) => {
    try {
        const result = await AsperaFileTransfer.downloadFile(remotePath, localSavePath);
        return result;
    } catch (error) {
        throw new Error(`下载失败:${error.message}`);
    }
};

4.2 在组件中使用

比如在App.js里实现上传功能和进度显示:

import React, { useEffect, useState } from 'react';
import { View, Button, Text, Alert } from 'react-native';
import { uploadFile, subscribeToProgress } from './AsperaTransfer';

const App = () => {
    const [transferProgress, setTransferProgress] = useState(0);

    useEffect(() => {
        // 订阅传输进度事件
        const progressSubscription = subscribeToProgress((progress) => {
            setTransferProgress(progress);
        });
        // 组件卸载时取消订阅
        return () => progressSubscription.remove();
    }, []);

    const handleUpload = async () => {
        try {
            // 替换为实际的本地文件路径和远程服务器路径
            const localFilePath = '/storage/emulated/0/Download/test.pdf';
            const remoteFilePath = '/server/storage/path/test.pdf';
            const result = await uploadFile(localFilePath, remoteFilePath);
            Alert.alert('成功', result);
            setTransferProgress(0);
        } catch (error) {
            Alert.alert('失败', error.message);
            setTransferProgress(0);
        }
    };

    return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <Button title="上传测试文件" onPress={handleUpload} />
            {transferProgress > 0 && (
                <Text style={{ marginTop: 20 }}>传输进度:{transferProgress}%</Text>
            )}
        </View>
    );
};

export default App;

5. 测试与注意事项

  • 测试前确保设备/模拟器有网络,Aspera服务器配置(地址、账号密码)正确,并且服务器允许该账号进行文件传输
  • Android 10+的文件权限需要特殊处理:要么申请MANAGE_EXTERNAL_STORAGE权限,要么使用MediaStore或SAF来获取文件路径,避免权限被拒绝
  • 调试时可以在Native层添加日志(比如Log.d("AsperaModule", "上传进度:" + progress)),方便定位问题
  • 如果遇到SDK初始化失败,先检查依赖是否全部添加,.aar文件是否正确放置在libs目录

内容的提问来源于stack exchange,提问作者Nikesh Yerneni

火山引擎 最新活动