안드로이드 N(누가) 버전이 나왔다.
여러가지 기능이 추가되었지만 마쉬멜로우 때도 그렇고 이번 누가버전에서도 권한에 대해서 꽤나 strict 모드로 전환되고 있는 추세인 것 같다.
보통 앱 내에 카메라 기능을 붙이고 이를 file 로 가져올 때 file:// scheme 값을 이용하여 가져왔지만,
누가버전에서부터 권한 문제로 이 기능을 더 이상 사용하지 못하고 대신에 새로운 interface 를 지원한다.
그래서 버전에 따라 분기를 둔 컨트롤러를 추가하여 해결하였다.
먼저 콜백 인터페이스는 간단히 RX 를 사용하여 만들었다.
import rx.functions.Action1 ;
public interface Callback < F > extends Action1 < F > {
}
아래는 컨트롤러코드
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.MediaStore
import android.support.v4.app.ActivityCompat.startActivityForResult
import android.support.v4.content.FileProvider
import java.io.File
import java.lang.ref.WeakReference
class FileProviderDispatcher {
private var activityWeakReference : WeakReference < Activity >
private var uri : Uri ? = null
constructor ( activity : Activity ) {
this . activityWeakReference = WeakReference ( activity )
}
fun setUri ( callback : Callback < String >) {
val file : File ? = makeFile () ?: return
if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . N ) {
activityWeakReference . get () ?. let { context ->
uri = FileProvider . getUriForFile ( context , "${context.packageName}.provider" , file !! )
callback . call ( file !! . absolutePath )
}
} else {
uri = Uri . fromFile ( file )
callback . call ( uri . toString ())
}
}
fun startImageCapture () {
Intent (). run {
activityWeakReference . get () ?. let { context ->
action = MediaStore . ACTION_IMAGE_CAPTURE
addFlags ( Intent . FLAG_GRANT_READ_URI_PERMISSION )
addFlags ( Intent . FLAG_GRANT_WRITE_URI_PERMISSION )
putExtra ( MediaStore . EXTRA_OUTPUT , uri )
startActivityForResult ( context , this , Constants . PICK_FROM_CAMERA , null )
}
}
}
private fun makeFile () =
File . createTempFile ( "prefix" , "suffix.jpg" , Environment . getExternalStorageDirectory ())
}
Activity 에서 이를 사용 시 아래와 같이 사용한다.
private fun takePicture () {
val fileProviderDispatcher = FileProviderDispatcher ( this )
fileProviderDispatcher . setUri ( Callback { path -> this . img_url = path })
fileProviderDispatcher . startImageCapture ()
}