Skip to content

Ztiany/android-media-selector

Repository files navigation

Lib Media Selector

Android 媒体文件选择库(图片与视频),支持 target api = 33

TODO:

  • 内置权限支持;
  • 支持视频预览;
  • 支持单选图片预览;
  • 支持 API 34 Grant partial access to photos and videos 交互。

1 支持应用内媒体文件选择

基于 boxing 封装,由于 boxing 官方不再维护,这里对相关问题进行了修复。包括:

  1. RotatePhotoView 依赖混乱导致的崩溃。
  2. Android 10 SQLiteException 崩溃问题,解决方案可以参考 replacement-for-group-by-in-contentresolver-query-in-android-q-android-10-ahttps://stackoverflow.com/questions/56823336/query-mediastore-on-android-q
  3. Android 11 invalid token limit,解决方案可以参考 limiting-number-of-rows-in-a-contentresolver-query-function
  4. 没有适配 Android 10 的 ScopedStorage。

另外,使用时需要配置好 FileProvider:

  • xml/file_path
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path name="app_internal" path="/" />
    <cache-path name="app_internal_cache" path="/" />
    <external-cache-path name="app_external_cache" path="/" />
    <external-files-path name="app_external" path="/" />
    <external-path name="app_external" path="/" />
</paths>
  • manifest
<provider android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.file.provider" android:exported="false"
    android:grantUriPermissions="true">
    <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_path" />
</provider>

除了 boxing,也可以考虑其他方案:

2 支持使用系统内置组件进行文件选择

SystemMediaSelector 用于调用系统相机或 SAF 获取图片或文件。

需要考虑的问题:

  1. Android 7.0 之后,需要适配 FileProvider。
  2. 获取的图片方向问题,需要通过 exif 修正。
  3. 系统返回的不是 file 路径,而是其他类型的 uri,需要通过相关方法转换。

相关参考:

3 支持图片裁剪

使用系统裁剪时发现不同设备厂商以及不同系统版本之间有行为不一致的问题,于是内置了第三方图片裁剪库 uCrop

其他可选裁剪库有:

4 Usage

class MainActivity : AppCompatActivity() {

    private val systemMediaSelector by lazy {
        newSystemMediaSelector(this, object : ResultListener {
            override fun onTakeSuccess(result: List<Uri>) {
                result.forEach {
                    Timber.e(it.toString())
                }
                showResult(result)
            }
        })
    }

    private val mediaSelector by lazy {
        newMediaSelector(this, object : ResultListener {
            override fun onTakeSuccess(result: List<Uri>) {
                result.forEach {
                    Timber.e(it.toString())
                }
                showResult(result)
            }
        })
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        systemMediaSelector.onRestoreInstanceState(savedInstanceState)
        mediaSelector.onRestoreInstanceState(savedInstanceState)
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        systemMediaSelector.onSaveInstanceState(outState)
        mediaSelector.onSaveInstanceState(outState)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        systemMediaSelector.onActivityResult(requestCode, resultCode, data)
        mediaSelector.onActivityResult(requestCode, resultCode, data)
    }

    ///////////////////////////////////////////////////////////////////////////
    // MediaStore
    ///////////////////////////////////////////////////////////////////////////
    fun selectOnePhotoByMediaStore(view: View) {
        mediaSelector.takePicture().start()
    }

    fun selectOnePhotoWithCameraByMediaStore(view: View) {
        mediaSelector.takePicture().needMediaLocation().enableCamera().start()
    }

    fun selectOnePhotoWithCameraAndCropByMediaStore(view: View) {
        mediaSelector.takePicture().needMediaLocation().enableCamera().crop().needGif().start()
    }

    fun selectMultiPhotoByMediaStore(view: View) {
        mediaSelector.takePicture().needMediaLocation().count(9).needGif().start()
    }

    fun selectOneVideoByMediaStore(view: View) {
        mediaSelector.takeVideo().needMediaLocation().start()
    }

    ///////////////////////////////////////////////////////////////////////////
    // Photos by Intent or SAF
    ///////////////////////////////////////////////////////////////////////////
    fun captureOnePhoto(view: View) {
        systemMediaSelector.takePhotoByCamera().start()
    }

    fun captureOnePhotoAndCrop(view: View) {
        systemMediaSelector.takePhotoByCamera().crop().start()
    }

    fun selectOnePhoto(view: View) {
        systemMediaSelector.takePhotoFromSystem().start()
    }

    fun selectOnePhotoAndCrop(view: View) {
        systemMediaSelector.takePhotoFromSystem().crop().start()
    }

    fun selectPhotos(view: View) {
        systemMediaSelector.takePhotoFromSystem().multiple(true).start()
    }

    ...

}

5 Installation

implementation 'io.github.ztiany:android-media-selector:1.1.1'

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published