# 扩展 SDK
除了核心SDK之外,我们还提供了扩展SDK,扩展SDK是一个依赖核心SDK的库,里面提供了核心SDK中所没有的各种小程序API。
之所以提供扩展SDK,是因为既要保证核心SDK足够轻量,又要保证小程序API足够丰富。核心SDK负责建立起运行小程序的基础框架并提供一小部分最不可获取的API,在权限方面仅保留了存储、相机、地理位置等基本权限,体积仅1MB多一点,扩展SDK则是作为核心SDK的补充而存在的,里面API将不断丰富和完善。
获取扩展 SDK
您可登录 资源下载中心 (opens new window) 下载 Android SDK 文件,扩展 SDK 也处于在所下载的压缩包中。
如果希望使用扩展SDK中的API,在gradle中依赖扩展SDK库即可:
implementation 'com.finogeeks.mop:plugins:x.y.z' //x.y.z须替换为具体的版本号
# 1. 扩展 SDK
# 1.1 扩展SDK中小程序API概览
| api名称 | api描述信息 | 
|---|---|
| getLocation | 获取位置信息 | 
| startRecord | 开始录音 | 
| stopRecord | 停止录音 | 
| RecorderManager | 全局唯一的录音管理器 | 
# 1.2 扩展SDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 获取位置信息 | getLocation | 
| 录制音频 | startRecord、recorderManager组件start | 
# 2. MapSDK
支持Map组件及位置API。
其依赖于核心SDK,做为地图、位置功能的补充。
其中提供的地图、定位能力依赖于第三方地图、定位SDK。支持高德地图|高德定位、百度地图|百度定位、谷歌地图|谷歌定位三种组合情况使用。
集成文档请参照「小程序SDK-Android SDK-Android 集成-6. MapSDK」。
# 2.1 MapSDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| Map组件 | 视图组件 | 
| MapContext | 一系列的api | 
| getLocation | 获取位置信息 | 
| startLocationUpdate | 连续定位 | 
| startLocationUpdateBackground | 连续定位(允许后台定位) | 
| openLocation | 查看位置 | 
| chooseLocation | 选择位置 | 
| choosePoi | 打开POI列表选择位置 | 
# 2.2 MapSDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 获取位置信息 | chooseLocation、getLocation、openLocation、choosePoi、Map组件 | 
# 3. 蓝牙SDK
使用蓝牙接口需要单独集成蓝牙SDK,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:bluetooth:x.y.z'
# 3.1 蓝牙SDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| 蓝牙-通用 | 一系列的api | 
| 蓝牙-低功耗中心设备 | 一系列的api | 
| 蓝牙-低功耗外围设备 | 一系列的api | 
| 蓝牙-信标 | 一系列的api | 
# 3.2 蓝牙SDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 蓝牙 | 蓝牙组件相关接口 | 
# 4. 声网SDK
不建议使用声网SDK来做视频推拉流,建议使用LiveSDK(见第12条)
使用声网相关的接口需要单独集成声网SDK,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:agora:x.y.z'
若您使用导入aar的方式接入声网SDK,需要额外添加声网依赖:
implementation 'io.agora.rtc:full-sdk:3.5.0'
# 4.1 声网SDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| init | 初始化声网SDK | 
| setRole | 设置客户端角色 | 
| join | 加入频道 | 
| publish | 开始推流 | 
| muteLocal | 本地静音 | 
| unmuteLocal | 解除本地静音 | 
| mute | 远端静音 | 
| unmute | 解除远端静音 | 
| renewToken | 刷新token | 
| setRemoteVideoStreamType | 设置订阅的视频流类型 | 
| destroy | 停止推流,释放资源 | 
# 4.2 声网SDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 录制音频 | join | 
| 摄像头 | publish | 
# 5. WebRTCSDK
使用WebRTC相关的接口需要单独集成WebRTCSDK,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:webrtc:x.y.z'
若您使用导入aar的方式接入WebRTCSDK,需要额外添加WebRTC依赖:
implementation 'org.webrtc:google-webrtc:1.0.32006'
# 5.1 WebRTCSDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| mediaDevices | MediaDevices相关接口,提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。 | 
| rtcPeerConnection | RTCPeerConnection相关接口,代表一个由本地计算机到远端的WebRTC连接。该接口提供了创建,保持,监控,关闭连接的方法的实现。 | 
| mediaStream | MediaStream相关接口,代表一个媒体内容的流。一个流包含几个轨道,比如视频和音频轨道。 | 
| mediaRecorder | MediaRecorder相关接口,提供媒体录制器等相关api。 | 
# 5.2 WebRTCSDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 摄像头 | getUserMedia | 
| 录制音频 | getUserMedia | 
# 6. 联系人SDK
使用联系人相关的接口需要单独集成联系人SDK,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:contact:x.y.z'
# 6.1 联系人SDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| addPhoneContact | 添加手机通讯录联系人API的名称 | 
# 7. 剪贴板SDK
使用剪贴板相关的接口需要单独集成剪贴板SDK,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:clipboard:x.y.z'
# 7.1 剪贴板SDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| setClipboardData | 设置剪贴板内容 | 
| getClipboardData | 获取剪贴板内容 | 
# 8. WeChatSDK
微信SDK的快捷接入,提供调起微信通过微信小程序获得登录、用户信息、手机号、支付的能力。
集成方式:
implementation 'com.finogeeks.mop:wechat:x.y.z'
并在项目的build.gradle文件中(如app/build.gradle)添加您在微信开放平台申请的微信APPID:
android {
    // ..其它配置省略
    defaultConfig {
    // ..其它配置省略
    resValue "string", "wechat_sdk_app_id", "您的微信SDKAPPID"
    }
}
注意
使用WeChatSDK须保证与您当前正在使用的核心SDK的版本一致,并且在2.37.13或以上。
注意
由于WeChatSDK需要覆盖IAppletHandler中的open-type相关的方法,具体为chooseAvatar、contact、feedback、getPhoneNumber、launchApp、shareAppMessage六个方法。
因此若您实现了IAppletHandler并实现了以上六个方法,WeChatSDK将会接管getPhoneNumber,剩余的五个方法请按以下方式迁移,若您未实现IAppletHandler或没有用到以上六个方法,可以忽略此处。
- 实现 - IWeChatOpenTypeHandler接口:- class MyWeChatAppletOpenTypeHandler : IWeChatOpenTypeHandler { override fun chooseAvatar(callback: IAppletHandler.IAppletCallback) { // 您的实现逻辑 } override fun contact(json: JSONObject): Boolean { // 您的实现逻辑 } override fun feedback(bundle: Bundle): Boolean { // 您的实现逻辑 } override fun launchApp(appParameter: String?): Boolean { // 您的实现逻辑 } override fun shareAppMessage( appInfo: String, bitmap: Bitmap?, callback: IAppletHandler.IAppletCallback ) { // 您的实现逻辑 } }
- 在核心SDK初始化成功后,设置您的实现类。(注意,同核心SDK一样,务必保证是在主进程中设置): - WeChatOpenTypeClient.instance.iWeChatOpenTypeHandler = MyWeChatAppletOpenTypeHandler()
注意
为了避免微信OpenSDK相关回调类冲突问题,WeChatSDK 从 2.39.11 版本开始,不再自动生成微信回调接收类 WXEntryActivity,请自行根据微信官方文档 Android接入指南 (opens new window) ,自行创建 WXEntryActivity ,并加入 WeChatSDK 回调处理方法,示例如下:
class WXEntryActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        FinWeChatWXEntry.handleWeChatIntent(this, intent)
        // 您的其它业务处理逻辑
        finish()
    }
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        FinWeChatWXEntry.handleWeChatIntent(this, intent)
        // 您的其它业务处理逻辑
        finish()
    }
}
# 8.1 WeChatSDK相关api概览
| api名称 | api描述信息 | 
|---|---|
| login | 唤起微信小程序,获取登录凭证,并将结果返回至FinClip小程序 | 
| getUserProfile | 唤起微信小程序,获取用户信息,并将结果返回至FinClip小程序 | 
| requestPayment | 唤起微信小程序,发起微信支付,并将结果返回至FinClip小程序 | 
| getPhoneNumber | 唤起微信小程序,获取到动态令牌,并将结果返回至FinClip小程序 | 
| navigateToWechatMiniProgram | 唤起微信小程序,参数如下: originId 微信小程序原始id envVersion 要打开的微信小程序版本,支持develop、trial、release,默认为release path 指定打开的微信小程序的路径 | 
# 9. Media SDK
2.38.0版本以后支持
video组件的边下边播需要集成此SDK才能实现。
集成方式:
android {
    packagingOptions {
        doNotStrip "*/arm64-v8a/libijkffmpeg.so"
        doNotStrip "*/arm64-v8a/libijkplayer.so"
        doNotStrip "*/arm64-v8a/libijksdl.so"
        doNotStrip "*/armeabi/libijkffmpeg.so"
        doNotStrip "*/armeabi/libijkplayer.so"
        doNotStrip "*/armeabi/libijksdl.so"
        doNotStrip "*/armeabi-v7a/libijkffmpeg.so"
        doNotStrip "*/armeabi-v7a/libijkplayer.so"
        doNotStrip "*/armeabi-v7a/libijksdl.so"
        doNotStrip "*/x86/libijkffmpeg.so"
        doNotStrip "*/x86/libijkplayer.so"
        doNotStrip "*/x86/libijksdl.so"
        doNotStrip "*/x86_64/libijkffmpeg.so"
        doNotStrip "*/x86_64/libijkplayer.so"
        doNotStrip "*/x86_64/libijksdl.so"
    }
}
dependencies {
    implementation 'com.finogeeks.mop:media:x.y.z' //x.y.z须替换为具体的版本号
    implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
}
在proguard-rules.pro文件中添加混淆规则:
# Media SDK
-keep public class com.finogeeks.finclip.plugins.media.player.ijk.FinIjkMediaPlayerFactory {
    public <init>();
}
-keep class com.finogeeks.finclip.plugins.media.player.ijk.IjkMediaPlayerOptionsApplier {
    public static <fields>;
    public static <methods>;
}
-keep class com.finogeeks.finclip.plugins.media.player.ijk.IjkMediaPlayerOptionsApplier$Applier {*;}
-keep class com.finogeeks.finclip.plugins.media.player.ijk.IjkMediaPlayerOptionsApplier$Options {*;}
#ijkplayer
-keep class tv.danmaku.ijk.media.player.** {*;}
-keep class tv.danmaku.ijk.media.player.IjkMediaPlayer{*;}
-keep class tv.danmaku.ijk.media.player.ffmpeg.FFmpegApi{*;}
集成Media SDK后,video组件的播放器实现,会从系统方案MediaPlayer自动切换到IjkMediaPlayer方案,无需做其他操作。
# 9.1 Media SDK的相关API
由于IjkMediaPlayer的配置项非常多,每个App的需求又不同,所以Media SDK将配置功能暴露给App开发者来调用。
class SampleApplication : MultiDexApplication() {
    override fun onCreate() {
        super.onCreate()
        IjkMediaPlayerOptionsApplier.setIjkMediaPlayerOptionsApplier(this) {
            it.setOption(
                IjkMediaPlayer.OPT_CATEGORY_PLAYER,
                "start-on-prepared",
                0
            ) // 禁止自动开始播放,由上层去控制
            it.setOption(
                IjkMediaPlayer.OPT_CATEGORY_PLAYER,
                "max-buffer-size",
                (1024 * 1024).toLong()
            ) // 最大缓冲大小,单位kb
            it.setOption(
                IjkMediaPlayer.OPT_CATEGORY_PLAYER,
                "packet-buffering",
                0L
            ) // 如此设置,才会在及时停止加载状态显示
            it.setOption(
                IjkMediaPlayer.OPT_CATEGORY_PLAYER,
                "enable-accurate-seek",
                1
            ) // 设置为精准seek
        }
        // 其他初始化代码……
    }
}
同时如上代码片段中的配置,是Media SDK的默认配置项,App开发者可以按照自己的需要制定相关的配置。
# 9.2 IjkMediaPlayer的一些问题
# 9.2.1 一直加载无法播放
在某些机型上,可能会出现一直加载无法播放的问题。通过Logcat,如果你发现了如下的bug形式:
Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x7783dd1920 in tid 25128 (ff_read), pid 22268
则很有可能,当前应用运行在Android 11且CPU架构为armv8a的机型上,需要在Manifest.xml文件的application标签下,加入一个属性android:allowNativeHeapPointerTagging="false"。具体可参考:[issues/5342](用arm64-v8a崩溃 Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x7783dd1920 in tid 25128 (ff_read), pid 22268 (rmdzh.ijkplayer) · Issue #5342 · bilibili/ijkplayer · GitHub (opens new window))
# 9.2.2 进度不精确
在拖动进度条或者切入切出全屏时,可能会出现进度回退的现象,这是因为播放器需要解析关键帧,只能从关键帧去播放,需要加入如下配置来开启精确seekTo。
it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1) // 设置为精准seek
需要注意的是,开启精确seekTo后,会导致在暂停状态下,seekTo后,画面不会更新的问题。
# 10. Share SDK
集成分享小程序功能,接管”更多“菜单面板中的”分享“按钮功能(核心SDK版本 ≥ 2.39.11)。
“分享”按钮默认为隐藏,需要自行配置为显示,详情请参考:设置小程序更多菜单。
如需自行接管“分享”按钮点击事件,请参考:回调方法。
集成方式:
implementation 'com.finogeeks.mop:share:x.y.z'
注意
使用ShareSDK须保证与您当前正在使用的核心SDK的版本一致,并且在2.39.11或以上。
# 10.1 微信分享
若需要开启微信分享功能,需要集成微信官方opensdk:
implementation 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.0'
并在项目的build.gradle文件中(如app/build.gradle)添加您在微信开放平台申请的移动应用APPID:
android {
    // ..其它配置省略
    defaultConfig {
    // ..其它配置省略
    resValue "string", "wechat_sdk_app_id", "您的微信开放平台移动应用下AppID"  
    }
}
注意
集成 ShareSDK 并使用其中的微信相关分享能力,需要先在微信开放平台申请AppID,这里填写的是移动应用下的AppID, 一般情况是wx开头,注意不是微信小程序的AppId,也不是微信小程序原始ID(gh开头),这些ID很容易搞混。
注意
为了避免微信OpenSDK相关回调类冲突问题,ShareSDK 不会自动生成微信回调接收类 WXEntryActivity,请自行根据微信官方文档 Android接入指南 (opens new window) ,自行创建 WXEntryActivity ,并加入 ShareSDK 回调处理方法,示例如下:
class WXEntryActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        FinShareWXEntry.handleWeChatIntent(this, intent)
        // 您的其它业务处理逻辑
        finish()
    }
    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        setIntent(intent)
        FinShareWXEntry.handleWeChatIntent(this, intent)
        // 您的其它业务处理逻辑
        finish()
    }
}
# 11. CastSDK
2.38.1版本以后支持
投屏SDK的快捷接入,提供调起播放视频的时候,可以投屏到其他支持相关协议(DLNA)的投屏设备(例如:电视)。
集成方式:
implementation 'com.finogeeks.mop:cast:x.y.z'
1、在要接入的工程的根目录 build.gradle 文件中添加如下配置:
 allprojects {
	repositories {
		
        maven { url 'http://4thline.org/m2' }
		maven { url 'https://jitpack.io' }
	}
}
2、在要接入的工程的目录 app/build.gradle 文件中添加如下配置:
 packagingOptions {
        
        exclude 'META-INF/beans.xml'
    }
# 12. LiveSDK
2.41.1 版本以后支持
直播SDK的快捷接入,提供直播推流、拉流、播放的能力。
集成方式:
implementation 'com.finogeeks.mop:live:x.y.z'
注意
直播SDK 不可和 WebRTC 以及 AgoraSDK一起使用
注意
在你要接入的工程中进行如下配置
        FinAppConfig.UIConfig uiConfig = new FinAppConfig.UIConfig();
        uiConfig.setUseNativeLiveComponent(true); // 此配置别遗漏
        FinAppConfig config = new FinAppConfig.Builder()
        // 省略其他配置
        .setUiConfig(uiConfig) // 记得要把uiConfig设置进去
        .build();
        FinAppClient.INSTANCE.init(this, config, new FinCallback<Object>() {
            @Override
            public void onSuccess(Object result) {
                // 初始化成功,可以开始使用直播组件
                // 这个也不要遗漏
                 AnyRtcLiverSDK.INSTANCE.install();
            }
            @Override
           public void onError(int code, String error) {
           }
            @Override
            public void onProgress(int status, String error) {
            }
        });
# 12.1 LiveSDK(live-player)相关api概览
| api名称 | api描述信息 | 
|---|---|
| play | 播放 | 
| stop | 停止 | 
| pause | 暂停 | 
| resume | 恢复 | 
| mute | 静音 | 
# 12.2 LiveSDK(live-pusher)相关api概览
| api名称 | api描述信息 | 
|---|---|
| start | 开始推流 | 
| stop | 停止推流,同时停止摄像头预览 | 
| pause | 暂停推流 | 
| resume | 恢复推流 | 
| startPreview | 开启摄像头预览 | 
| stopPreview | 关闭摄像头预览 | 
| switchCamera | 切换前后摄像头 | 
# 12.2.1 LiveSDK涉及到的敏感权限
| 权限 | 相关接口、组件 | 
|---|---|
| 摄像头 | 初始化的时候就会请求权限 | 
| 录制音频 | 初始化的时候就会请求权限 | 
# 13. XLogSDK
从 2.40.5 版本开始,核心SDK中将不再包含XLog,即不再包含将日志持久化存储在本地的功能。
若有持久化日志的需求,可以选择集成XLogSDK,并开启对应的配置项。
集成方式:
implementation 'com.finogeeks.mop:xlog:x.y.z'
相关配置:
FinAppConfig config = new FinAppConfig.Builder()
    // 开启日志记录,默认是false
    .setDebugMode(true)
    // 设置日志等级,默认是LEVEL_NONE,即不会输出、记录日志
    .setLogLevel(XLogLevel.LEVEL_VERBOSE)
    // 设置日志文件目录,默认为 /data/data/${packageName}/files/fino_xLog
    // 若自定义了日志保存路径,初始化SDK时请自行提前确保有该路径的写入权限,否则可能导致日志文件无法正常写入
    .setXLogDir(logDir)
    // 设置日志最大留存时间,单位为秒,若不设置则由XLog自行管理
    .setLogMaxAliveSec(24*3600)
    // 其它配置省略
    .build();
FinAppClient.init(application, config, finCallback);
注意,若不集成XLogSDK,以上配置项中 setXLogDir 和 setLogMaxAliveSec 将无效,但 setDebugMode 和 setLogLevel 依然生效,但仅会输出在控制台中而不会持久化日志。
日志导出:
/**
 * 导出日志
 *
 * @param context
 * @param appId 导出指定小程序id的日志,若传空则导出主进程的日志
 * @param date 导出指定日期的日志文件,若传空则导出主进程或指定小程序的所有日志
 * @param exportDir 导出到指定目录
 */
FinAppClient.INSTANCE.exportLogFile(context, appId, date, exportDir);
使用示例
导出主进程的所有日志:
boolean result = FinAppClient.INSTANCE.exportLogFile(context, null, null, exportDir);
导出主进程的指定日期日志:
boolean result = FinAppClient.INSTANCE.exportLogFile(context, null, date, exportDir);
导出指定小程序的所有日志:
boolean result = FinAppClient.INSTANCE.exportLogFile(context, appId, null, exportDir);
导出指定小程序的指定日期日志:
boolean result = FinAppClient.INSTANCE.exportLogFile(context, appId, date, exportDir);
注意:导出前请确保指定的导出位置
exportDir有写入权限,否则可能会导出日志失败。
# 14. CalendarSDK
使用日历相关接口需要单独集成日历SDK,需要核心SDK版本高于2.40.13,集成后接口即可生效,无需配置。
集成方式:
implementation 'com.finogeeks.mop:calendar:x.y.z'
# 14.1 CalendarSDK 相关api概览
| api名称 | api描述信息 | 
|---|---|
| addPhoneCalendar | 添加日历普通事件 | 
| addPhoneRepeatCalendar | 添加日历重复事件 | 
# 15. MediaPickerSDK
使用图片选择器需要单独集成MediaPickerSDK,需要核心SDK版本高于2.48.5。
# 15.1 集成方式:
implementation "com.finogeeks.mop:media_picker:x.y.z"
# 15.2 依赖其他图片下载库:
// 根据项目内部已有的下载来适配即可,不一定要用glide
// 如果已经依赖glide,就可以不用再依赖了。依赖其他图片下载库也行,根据自己的项目来即可
implementation 'com.github.bumptech.glide:glide:4.1.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.1.0'
# 15.3 配置图片处理器
// 继承类:com.finogeeks.mop.picker.delegate.ImageEngineDelegate#ImageEngineDelegate
// 示例如下:
// 注意,具体每个方式的实现都是自定义的,不一定按照示例来,根据各自的需求处理。
class MyImageEngineDelegate : ImageEngineDelegate() {
    /**
     * 加载图片
     *
     * @param context   上下文
     * @param url       资源url
     * @param imageView 图片承载控件
     */
    override fun loadImage(context: Context?, url: String?, imageView: ImageView?) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        Glide.with(context)
            .load(url)
            .into(imageView)
    }
    override fun loadImage(
        context: Context?,
        imageView: ImageView?,
        url: String?,
        maxWidth: Int,
        maxHeight: Int
    ) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        val requestOptions = RequestOptions()
            .override(maxWidth, maxHeight) // 指定宽高
        Glide.with(context)
            .load(url)
            .apply(requestOptions)
            .into(imageView)
    }
    /**
     * 加载相册目录封面
     *
     * @param context   上下文
     * @param url       图片路径
     * @param imageView 承载图片ImageView
     */
    override fun loadAlbumCover(context: Context?, url: String?, imageView: ImageView?) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        val requestOptions = RequestOptions()
            .override(180, 180).sizeMultiplier(0.5f).transform(RoundedCorners(8))
            .centerCrop().placeholder(R.drawable.ps_image_placeholder) // 指定宽高
        Glide.with(context)
            .load(url)
            .apply(requestOptions)
            .into(imageView)
    }
    /**
     * 加载图片列表图片
     *
     * @param context   上下文
     * @param url       图片路径
     * @param imageView 承载图片ImageView
     */
    override fun loadGridImage(context: Context?, url: String?, imageView: ImageView?) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        val requestOptions = RequestOptions()
            .override(200, 200).centerCrop().placeholder(R.drawable.ps_image_placeholder) // 指定宽高
        Glide.with(context)
            .load(url)
            .apply(requestOptions)
            .into(imageView)
    }
    override fun pauseRequests(context: Context?) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        Glide.with(context).pauseRequests()
    }
    override fun resumeRequests(context: Context?) {
        if (!ActivityCompatHelper.assertValidRequest(context)) {
            return
        }
        Glide.with(context).resumeRequests()
    }
}
# 15. 4 配置生效
 // 在你的Application的onCreate回调里面注册
 // 设置之后就会使用内部图片选择器,而不是打开手机内置的相册或者文件管理器
FinMediaPickerSDK.setImageEngineDelegateClass(MyImageEngineDelegate::class.java)
