友盟+搜索

{{errorMsg}}

准备工作

1.开通服务,创建空间用于文件存储,参考 接入指引

2.通过 控制台 进入 SDK 下载,生成最新SDK

3.语言选择 Android,并上传私钥签名过的 APK 包 (APK 包的内容不做要求,可以不是最终的应用;但是私钥跟安全图片必须是一一对应的,如果私钥发生改变需重新生成安全图片) (如果您对什么是私钥,以及如何通过私钥加密 App 不甚了解,建议网上找一下类似文章学习掌握,例如 这篇),点击 “生成最新SDK”

4.下载SDK,生成成功的SDK包含“专属”信息,仅能被您所上传的Apk文件应用所在的工程使用。

运行 Demo

1.下载demo:点击下载 ,打开后示例如下:

如上所示,media.sdk.android.demo是Demo工程,MediaSDK是顽兔多媒体SDK,MediaSDKAndroidDemo.apk是可以直接运行的Demo安装文件。

2.将media.sdk.android.demo和MediaSDK导入到IDE(Eclipse、IDEA、AndroidStudio)中,并使media.sdk.android.demo依赖MediaSDK。

3.将media.sdk.android.demo工程生成签名APK,进入控制台将APK上传生成SDK。下载SDK并解压,从res/drawable目录中得到安全图片yw_1222.jpg。然后替换掉MediaSDK中对应的安全图片。

4.将media.sdk.android.demo项目下DemoApp.java中NAMESPACE的值修改为你创建的namespace。

5.生成签名的APK(签名信息与第3步中生成APK的签名必须一致),下载并安装到手机上。

6.通过Demo应用上传一张图片,上传成功会返回图片的URL信息。

7.通过控制台的空间管理功能,浏览通过Demo应用上传的图片,如下图。

工程配置

开发者可以直接在 Demo 的基础上定制自己的逻辑,完成应用开发,这部分开发者可以忽略本节的配置说明。还有很多开发者,希望以相对干净的方式引入对 MediaSDK 的依赖,本节内容就是为这部分开发者准备的。

 添加 SDK

针对不同的开发软件有不同的添加方式,如果都不能正常添加,使用最后的简单粗暴方法。

添加到 Eclipse 工程

如果项目IDE为Eclipse,则直接通过属性中的依赖 lib 工程将客户端 SDK 依赖进来。如下图:

在您的项目工程中依赖之前导入的 SDK:

添加到 Android Studio 工程

如果项目 IDE 为 Android Studio 并使用 Gradle 来管理项目,可以:

1.以模块的方式将 MediaSDK 引入到开发者的目标工程中

2.成功引入 MediaSDK 依赖的目标工程目录

3.在 app 的 build.gradle 中加入 MediaSDK 依赖

dependencies {
    ......
    compile project(':MediaSDK')
}

如果不使用 Gradle,开发者也可以使用 Android Studio 的添加依赖功能,加入 MediaSDK 依赖,步骤如下:

1.打开Android studio,并打开开发的工程 2.导入 Module,File -> Import Module

3.选择下载好的sdk文件夹,如下图

4.添加依赖:选择project,右键,点击open module setting,打开 project structure

5.选择app,添加 module dependency,如下图

暴力添加

如果以上正常方法无法成功添加,可以采取最简单粗暴的方法:将客户端SDK中的所有文件拷贝到对应的自己项目中工程中,且 AndroidManifest.xml 文件内容要合并(主要是 application 和 uses-permission 标签下的内容),项目目录结构要一致。

添加安全图片

前一节中,我们了解到,有一张标示应用身份的安全图片。开发者需要把它放置到 SDK 工程的 res/drawable 目录中,且安全图片的文件名称不可修改。添加安全图片的步骤如下:

1.将生产的安全图片 yw_1222.jpg 替换掉 MediaSDK res/drawable 目录下的同名图片

2.为方便调试,可以将生产签名的配置加入到 app 的 build.gradle 中

signingConfigs {
    debug{
        storeFile file("demo_media_app.jks")
        storePassword "xxxxxxxxx"
        keyAlias "media001"
        keyPassword "xxxxxxxxxxxxxxx"
    }
}

SDK 接口说明

SDK初始化

使用多媒体服务之前需要先初始化,初始化分为两步:

  1. 初始化 AlibabaSDK
  2. 获取多媒体服务 MediaService 对象

示例代码

AlibabaSDK.asyncInit(context, new InitResultCallback() {
     @Override
     public void onSuccess() {
         Log.e(TAG, "-----initTaeSDK----onSuccess()-------" );
     }

     @Override
     public void onFailure(int code, String msg) {
         Log.e(TAG, "-------onFailure----msg:" + msg + "  code:" + code);
     }
 });
MediaService mediaService = AlibabaSDK.getService(MediaService.class);

文件上传

上传一张图片的步骤如下:

  1. 获得 MediaService 对象
  2. 构造 UploadListener,用于封装上传回调逻辑
  3. 构造 UploadOptions,用来精细化控制上传行为(可选)
  4. 调用 MediaService 对象的 upload 方法进行上传
  5. 可暂停、恢复或取消上传动作(小文件上传不建议使用)

接口描述

UploadListener(上传回调)

public interface UploadListener {

    void onUploading(UploadTask uploadTask);

    void onUploadFailed(UploadTask uploadTask, FailReason failReason);

    void onUploadComplete(UploadTask uploadTask);

    void onUploadCancelled(UploadTask uploadTask);

}

UploadTask(由 UploadListner 回调时提供)

public interface UploadTask {

    //自定义tag
    public String getTag();

    //文件大小
    public long getTotal(); 

    //已上传大小
    public long getCurrent();

    //原文件
    public File getFile();

    //上传完成信息
    public Result getResult();

}

public static class Result {

    public final String url;
    public final String dir;
    public final String name;

    //开发者自定义内容,会被魔法变量渲染
    public final String returnBody;

    // 开发者服务器回调响应内容
    public final String customBody;

}

UploadOptions.Builder(上传选项)

public static class Builder {

    /**
     * 服务端文件名字 ,默认取File name
     * @param aliases
     * @return
     */
    public Builder aliases(String aliases) ;


    /**
     * 服务端文件目录 默认为空
     * @param dir
     * @return
     */
    public Builder dir(String dir);


    /**
     * 自定义tag
     * 
     * @param tag
     * @return
     */
    public Builder tag(String tag) ;


    /**
     * 限制文件大小
     * 
     * @param size
     * @return
     */
    public Builder limitSize(long limitSize);


    /**
     * 上传完成自定义回调:CallBackRequest
     * 
     * @param back
     * @return
     */
    public Builder callBackRequest(CallBackRequest callBackRequest) ;


    /**
     * 文件上传自定义meta map(高级用法,普通使用不必关注)
     * 
     * @param metaMap
     * @return
     */
    public Builder customMetaMap(HashMap<String, String> metaMap);


    /**
     * 文件上传 自定义变量map,dir ,aliases ,callback body中可以引用(高级用法,普通使用不必关注)
     * 
     * @param varMap
     * @return
     */
    public Builder customVariableMap(HashMap<String, String> varMap);


    /**
     * 开启MD5文件摘要校验,默认为true
     * 
     * @param enable
     * @return
     */
    public Builder checkMd5sum(boolean enable);

    /**
     * 开启断点续传(与blockSize配合使用)
     * 
     * @param needRecorder
     * @return
     */
    public Builder needRecorder(boolean needRecorder);


    /**
     * 自定义分块大小:区间为(500k-5M,默认2M)
     * @param blockSize
     * @return
     */
    public Builder blockSize(long blockSize) ;


    /**
     * 扩展的上传策略
     * 
     * @param policyMap
     * @return
     */
    public Builder policyMap(HashMap<String, String> policyMap);

}

MediaService-上传文件

/**
 * 
 * @param file 需要上传的文件对象
 * @param namespace 图片访问域名的前缀,通过tae管理控制台创建和管理:http://tae.taobao.com/
 * @param listener  上传回调监听
 * @return  上传任务Id
 */
public String upload(File file, String namespace, UploadListener listener);

/**
 * 
 * @param file  需要上传的文件对象
 * @param namespace 上传的空间
 * @param uploadOptions  上传选项参数
 * @param listener  回调监听
 * @return 上传任务Id
 */
public String upload(File file, String namespace,
    UploadOptions uploadOptions, UploadListener listener);

/**
 * 
 * @param data              byte数组
 * @param dataName          资源名
 * @param namespace         空间 
 * @param uploadOptions     上传配置项
 * @param listener          上传回调监听
 * @return                  上传任务Id
 */
public String upload(byte[] data, String dataName, String namespace,
    UploadOptions uploadOptions, UploadListener listener);

/**
 * 暂停上传
 * @param uploadTaskId 上传任务Id
 * @return
 */
public boolean pauseUpload(String uploadTaskId);


/**
 * 继续上传,支持断点续传
 * @param uploadTaskId 上传任务id
 * @param uploadListener 上传回调监听
 */
public void resumeUpload(String uploadTaskId, UploadListener uploadListener);


/** 取消上传
 * 
 * @param uploadTaskId      上传任务Id
 */
public void cancelUpload (String uploadTaskId);

样例代码

MediaService mediaService = AlibabaSDK.getService(MediaService.class);

UploadListener listener = new UploadListener() {

    @Override
    public void onUploading(UploadTask uploadTask) {
        Log.e(TAG, "---上传中---已上传大小:"+uploadTask.getCurrent()
                                   +" 总文件大小:"+uploadTask.getTotal());
    }

    @Override
    public void onUploadFailed(UploadTask uploadTask, String failMessage) {
        Log.e(TAG, "---上传失败---");
    }

    @Override
    public void onUploadComplete(UploadTask uploadTask) {
        Log.e(TAG, "---上传成功---URL:"+uploadTask.getResult().url));
    }

    @Override
    public void onUploadCancelled(UploadTask uploadTask) {
        Log.e(TAG, "---上传取消---");
    }
};

//简单上传
mediaService.upload(new File("/storage/sdcard1/b.png"),"iamge", listener);

//带上传选项
UploadOptions options = new UploadOptions.Builder().dir("风景")
    .aliases("黄山01").build();

String taskId = mediaService.upload(new File("/storage/sdcard1/a.png"),"iamge",
    options, listener);

mediaService.pauseUpload(taskId);
mediaService.resumeUpload(taskId,listener);
mediaService.cancelUpload(taskId);

文件加载

文件加载可以不依赖 SDK 提供的API,直接通过URL的方式进行加载。需要使用多媒体服务提供的缩略、裁剪、水印等丰富的图片处理功能,开发者也可以通过向图片URL指定图片处理参数,或参数别名来实现(详情参考图片处理章节)。

如果用户希望获得图片加载的统计数据和调用上的一些优化,则建议使用 SDK 提供的方法进行。通过 SDK 加载一张图片的步骤如下:

  1. 获得 MediaService 对象
  2. 构造 LoadingListener,用于封装加载回调逻辑
  3. 构造 LoaderOptions,用来传递用户参数(可选)
  4. 构造 ImageOptions,用来指定图片处理参数(可选)
  5. 调用 MediaService 对象的 loadImage 方法进行加载图片

接口描述

LoadingListener(加载回调)

public interface LoadingListener {

    void onLoadingFailed(ImageLoaderTask loaderTask,String failMessage);

    void onLoadingComplete(ImageLoaderTask loaderTask);

}

ImageLoaderTask(由 LoadingListener 回调时提供)

public class ImageLoaderTask {

    //图片uri
    public String getUri();

    //自定义Tag
    public Object getTag();

    //加载成功图片信息
    public ImageInfo getImageInfo();

}

public interface ImageInfo {

    public byte[] getData();

    public Bitmap getBitmap();

    public Map<String, String> getMetaMap();
}

LoaderOptions.Builder(加载选项)

public static class Builder {
    //自定义tag
    public Builder tag(Object tag) ;
}

ImageOptions.Builder(图片处理参数)

public static class Builder {

    /**
     * 
     * @param width :范围:[1-4096] , 单独使用(height不设置):width等比缩放 .width=120,
     *            代表width缩放到 120px,height按照相同比例缩放 。
     * @return
     */
    public Builder width(int width) ;



    /**
     * 
     * @param height:范围:[1-4096] ,单独使用(width<= 0):height等比缩放
     *            .height=120,代表height缩放到 120px, width按照等比例缩放 。
     * @return
     */
    public Builder height(int height) ;



    /**
     * (e) 定义了同时配置width,height图片如何缩放的规制, 此参数需要同时指定width ,height 参数才能生效。
     * 长边短边的定义:长边:是指原尺寸与目标的比值大那条边 。如原图 400 * 200 ,缩放为800 * 100 (400/800=0.5,
     * 200/100= 2,0.5 < 2 ), 所以在这个缩放 中 200 那条是长边,400是短边 。
     * 
     * @param edge: edge = false,以长边的缩放比例作为该图片的缩放比例 edge =
     *            true,以短边的缩放比例作为该图片的缩放比例 默认为false
     * @return
     */
    public Builder edge(boolean edge);


    /**
     * (Q) 设置图片质量
     * 
     * @param quality :绝对质量,范围:[0-100 ] ,, 注意点:获取的图片quality<=
     *            原图的quality,该参数只对jpg和png格式图片有效 。
     * @return
     */
    public Builder quality(int quality);


    /**
     * (x) 设置图片尺寸调整倍数:默认1 ,必须保证转换后的heigh,width 在 (1 -4096)区间内
     * 
     * @param multiple : 图片按照指定比例缩放 ,如原图尺寸 200 * 100 ,设置multiple =3 ,得到尺寸为600
     *            *300的图 片, 当与 width、height与缩放参数混合使用时,即对width和 height乘
     *            x倍,再进行缩放 , 原图 400 *200 , 使用 设置 width = 50 ,height = 50
     *            ,multiple = 2,(等同于 "width =100 ,height =100") 后,得到 100 *
     *            50的图片 。
     * @return
     */

    public Builder multiple(int multiple);


    /**
     * (i) 是否固定图片的宽高,进行非缩放裁剪
     * 
     * @param immobilize: 默认为false ,不固定(0) 使用 immobilize裁剪 时,会以图片中心为心指定 w和 h的区域.
     *            ,如原图 200 * 400 使用 参数 100w,100h,immobilize= true ,cut =true
     *            会裁剪出图片中心 100 * 100 的区域 。 此参数需要与 width ,height 、cut = true
     *            同时使用,单独使用无意义 。 冲突: immobilize = true 和 edge同时存在,以
     *            immobilize为准,忽略 edge
     * @return
     */
    public Builder immobilize(boolean immobilize);



    /**
     * (c) 是否进行裁剪,默认false,不裁剪
     * 
     * @param cut: 对缩放后超出范围的图片内容进行剪 裁,这 种情况一般发生在按照短边优先的等比缩放中。
     *            缩放会以图片中线为心,进行上下左右的 裁剪,得到相应的尺寸 。 如原图 200 * 400,
     *            使用参数100w,100h,edge = 1,cut = true 首先按照短边 , 优先缩放一张 100 *200
     *            的图片,之后按照中 线裁剪高度,得到一张 100 * 100 的图片 。 此参数需要配合 width,height,
     *            edge 或 width , height , immobilize = true 同时使用,单独无意义 。
     *            width ,height, edge 表示缩放后裁剪 , width ,height , immobilize =
     *            true 表示不缩放裁剪 冲突: 当有 immobilize = true, edge 时存在,忽略edge 参数
     * @return
     */
    public Builder cut(boolean cut) ;



    /**
     * (o)
     * 
     * @param orientation:默认false:按原图默认处理 true:表示按原图 EXIF信息自动旋转图片
     * @return
     */
    public Builder orientation(boolean orientation);


    /**
     * (r) 对图片进行旋转:
     * 
     * @param rotate 默认 0:不旋转
     * @return
     */
    public Builder rotate(int rotate) ;


    /**
     * (l)
     * 
     * @param limit true 生成的图片大于原图将返回原图, 默认false 不做处理
     * @return
     */
    public Builder limit(boolean limit);


    /**
     * (b) 设置图片的亮度:取值范围[-100,100],默认0,-100最暗,100 最亮
     * 
     * @param brightness
     * @return
     */
    public Builder brightness(int brightness) ;

    /**
     * (d) 设置图片对比度:取值范围[-100,100],默认0,-100对比度最低,100对比度最高
     * 
     * @param contrast
     * @return
     */
    public Builder contrast(int contrast) ;


    /**
     * 设定获取图片的格式 默认webp
     * 
     * @param type
     * @return
     */
    public Builder format(ImageFormat format) ;


    /**
     * 从指定位置,裁剪指定大小的图片 ,以图片左上角的点为原点,
     * 
     * @param x 起始点x坐标
     * @param y 起始点y坐标
     * @param width 需要裁切的宽度 ,width = 0 ,裁切到图片边缘
     * @param height 需要裁切的高度 , height = 0 ,裁切到图片边缘
     * @return
     */
    public Builder advanceCut(int x, int y, int width, int height);


    /**
     * 设置水印
     * @param waterMark
     * @return
     */
    public Builder waterMark(WaterMark waterMark);

}

ImageOptions.WaterMark(图片水印)

public static class WaterMark {

    /**
     * 水印图片
     * @param logoPath  水印logo图片的路径
     * @param logoFileName 水印logo文件名字,非空
     */
    public WaterMark(String logoPath);


    /**
     * 水印文字
     * @param fontText 水印文字内容,非空
     * @param fontType 水印字体类型,非空
     */
    public WaterMark(String fontText, FontType fontTyp);


    /**
     * 设置水印文字 字体大小  
     * @param fontSize 默认:40 ,取值范围[0-1000]
     */
    public void setFontSize(int fontSize);

    /**
     * 设置水印文字 字体颜色
     * @param fontColor  默认:#000000,格式为RRGGBB
     */
    public void setFontColor(int fontColor);


    /**
     *  设置垂直间距
     * @param distanceY 默认10,范围:[1-4096]
     */
    public void setDistanceY(int distanceY);


    /**
     * 设置水平间距
     * @param distanceX 默认10,范围:[1-4096]
     */
    public void setDistanceX(int distanceX);


    /**
     * 透明度,
     * @param transparency 默认100 不透明,范围:[0-100]
     */
    public void setTransparency(int transparency) ;


    /**
     * 位置
     * 
     * @param position 默认值 WatermarkPosition.RIGHT_BOTTOM
     */
    public void setPosition(WatermarkPosition position);

}

Constants(常量集,含所有错误码)

public final class Constants {

    public static final int KB = 1024;
    public static final int MB = KB * KB;

    //所有错误码
    public static final class Error {

        public static final String NETWORK = " network is not connected";
        public static final String UNKNOWN = " unknown error";
        public static final String INIT_CONTEXT_WITH_NULL = " context can not be initialized with null";
        public static final String INIT_APPKEY_WITH_NULL = " appkey can not be initialized with null";
        public static final String INIT_TOKEN_WITH_NULL = " tokenGenerator can not be initialized with null";

        public static final String BLANK_URI = "uri is blank";

        public static final String SERVER_TOKEN = "InvalidToken";
        public static final String SERVER_SID = "InvalidSid";

        public static final String LISTENER = "listener == null";
        public static final String NOT_INIT = "upload must be init with UploadEngine before using";
        public static final String NOT_TASK = " upload task cannot be found";
        public static final String FILE_BLANK = "file is not exists or is not file or is empty";

        public static final String OPTIONS_BLOCKSIZE = " options blockSize cannot be <= 0 ";
        public static final String NAMESPACE_EMPTY = " namespace cannot be empty";
        public static final String RESUME_FAIL = " resumed upload fail";
        public static final String RECOVERY_FAIL = "recovery upload failed";

        public static final String DATA_EMPTY = "data cannot be empty";

        public static final String TOKEN_EMPTY = " generateToken cannot be empty";

    }

    /*
     * OK 操作成功 200 BadRequest 非法请求 400 InvalidArgument 参数错误 400 Unauthorized
     * 授权失败 401 ResourceNotFound 文件或目录不存在 404 InternalError 服务端内部错误 500 Timeout
     * 请求超时,服务端超时 504 MediaTypeError 文件类型校验失败 400 SignError MD5校验出错(文件内容被修改) 400
     * NameDuplicated 文件名称或目录名称重复 400 LimitExceeded 文件大小超过限制 400 InvalidToken
     * Token非法或过期 400 InvalidSid SID非法 400 UnauthorizedSid SID无权限 401
     * InvalidNamespace Namespace非法 400 ContextExpired 分片上传,上下文失效、过期 400
     * NamespaceNotFound 没有开通服务 400 NonEmpty 非空目录不能删除 400 CallbackError
     * 上传成功,但回调失败 (包括业务服务器异常、tae服务器异常以及tae服务器间的网络异常) 200
     */

    public static final class ImageLoader {

        public static enum ImageFormat {
            PNG(FileTypeEnum.TYPE_PNG), WEBP(FileTypeEnum.TYPE_WEBP), BMP(
                FileTypeEnum.TYPE_BMP), JPG(FileTypeEnum.TYPE_JPG);

            private FileTypeEnum typeEnum;

            private ImageFormat(FileTypeEnum type) {
                this.typeEnum = type;
            }

            public FileTypeEnum getFileTypeEnum() {
                return typeEnum;
            }
        }

        public static enum FontType {
            /**
            * 文泉驿正黑
            */
            ZHENHEI("wqy-zenhei"),

            /**
            * 文泉微米黑
            */
            MICROHEI("wqy-microhei"),

            /**
            * 方正书宋
            */
            SHUSONG("fangzhengshusong"),

            /**
            * 方正楷体
            */
            KAITI("fangzhengkaiti"),

            /**
            * 方正黑体
            */
            HEITI("fangzhengheiti"),

            /**
             * 方正仿宋
             */
            FANGSONG("fangzhengfangsong"),

            DROIDSANSFALLBACK("droidsansfallback");

            private String format;

            private FontType(String format) {
                this.format = format;
            }

            public String getFormat() {
                return format;
            }
        }

        public static enum WatermarkPosition {

            LEFT_TOP(1), LEFT_CENTER(4), LEFT_BOTTOM(7), CENTER_TOP(2), CENTER_CENTER(
                    5), CENTER_BOTTOM(8), RIGHT_TOP(3), RIGHT_CENTER(6), RIGHT_BOTTOM(
                    9);

            private int format;

            private WatermarkPosition(int format) {
                this.format = format;
            }

            public int getFormat() {
                return format;
            }

        }
    }
}

加载文件

/**
 * 
 * @param uri               图片uri
 * @param listener          图片加载回调监听
 */
public void loadImage(String uri, LoadingListener listener);

/**
 * 
 * @param uri               图片uri
 * @param loaderOptions     加载选项
 * @param listener          图片加载回调监听
 */
public void loadImage(String uri, LoaderOptions loaderOptions,LoadingListener listener);

/**
 * 
 * @param uri               图片uri
 * @param options           图片参数
 * @return                  经过图片参数修饰后的uri
 */
public String getImageUri(String uri, ImageOptions options);

样例代码

MediaService mediaService = AlibabaSDK.getService(MediaService.class);

LoadingListener loadingListener = new LoadingListener() {

    @Override
    public void onLoadingFailed(ImageLoaderTask loaderTask,  String failMessage) {
        Log.e(TAG, "----图片加载失敗 - failMessage:" + failMessage);
    }

    @Override
    public void onLoadingComplete(ImageLoaderTask loaderTask) {
        Log.e(TAG, "----图片加载完成----");

    }
};

LoaderOptions loaderOptions = new LoaderOptions.Builder()
            .userKey(String.valueOf(System.currentTimeMillis())).build();

ImageOptions options = new ImageOptions.Builder()
        .width(500)
        .height(400)
        .waterMark(
                new WaterMark("你好",
                  Constants.ImageLoader.FontType.HEITI)).build();
String imageUri = mediaService.getImageUri(URI, options) ;
mediaService.loadImage(imageUri,loaderOptions,loadingListener);

兼容性

支持android 2.2 (version 8)及其以上版本