훌륭한 개발자가 되기 위하여
[Android | Kotlin] 안드로이드 기본 앱과 연동하기 본문
주소록 앱 연동하기
주소록 앱에서 데이터를 가져오려면 퍼미션을 설정
<uses-permission android:name="android.permission.READ_CONTACTS" />
주소록의 목록 화면을 띄우는 코드
- ContactsContractContacts.CONTENT_URI : 모든 사람의 데이터
- ContactsContractCommonDataKinds.Phone.CONTENT_URI : 전화번호가 있는 사람
- ContactsContractCommonDataKinds.Email.CONTENT_URI : 이메일 정보가 있는 사람
// 주소록 목록 출력
val intent = Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI)
requestContactsLauncher.launch(intent)
- 목록에서 한 사람을 선택하여 되돌아오면 ActivityResultCallback의 onActivityResult( ) 함수가 자동으로 실행
// 주소록에서 사옹자가 한 사람을 선택했을 때 실행되는 함수
requestContactsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult())
{
if (it.resultCode == RESULT_OK) {
Log.d("kim", "${it.data?.data}")
}
}
- 주소록 앱이 전달한 문자열
- 식별값을 조건으로 주소록 앱에 필요한 데이터를 구체적으로 다시 요청
// 콘텐츠 프로바이더로 필요한 데이터 요청
requestContactsLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult())
{
if (it.resultCode == RESULT_OK) {
val cursor = contentResolver.query(
it!!.data!!.data!!,
arrayOf<String>(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
),
null,
null,
null
)
Log.d("kim", "${cursor?.count}")
if (cursor!!.moveToFirst()) {
val name = cursor?.getString(0)
val phone = cursor?.getString(1)
binding.resultContact.text = "name: $name, phone: $phone"
}
}
}
갤러리 앱 연동하기
갤러리 앱 연동은 인텐트로 갤러리 앱의 목록 화면을 띄우거나 갤러리 앱의 콘텐츠 프로바이더로 데이터를 가져오는 작업
이미지 작업 시 고려 사항
- 안드로이드에서 이미지는 Drawable이나 Bitmap 객체로 표현합니다.
- Bitmap 객체는 BitmapFactory로 생성합니다.
- BitmapFactory로 이미지를 생성할 때는 OOM 오류를 고려해야 합니다.
- Glide나 Picasso 같은 이미지 처리 라이브러리를 이용하는 것이 효율적일 수 있습니다.
Bitmap 이미지는 BitmapFactory 클래스의 'decode'로 시작하는 다음과 같은 함수로 생성
- BitmapFactory.decodeByteArray( ) : byte[ ] 배열의 데이터로 비트맵 생성
- BitmapFactory.decodeFile( ) : 파일 경로를 매개변수로 지정하면 그 파일에서 데이터를 읽을 수 있는 FileInputStream을 만들어 decodeStream( ) 함수 이용
- BitmapFactory.decodeResource( ) : 리소스 이미지로 비트맵 생성
- BitmapFactory.decodeStream( ) : InputStream으로 읽은 데이터로 비트맵 생성
- OOM이란 앱의 메모리가 부족해서 발생하는 오류
- 용량이 큰 이미지를 불러올 때 발생
- 이미지 크기를 줄일 때는 BitmapFactory.Option 객체의 inSampleSize 속성을 이용
// 옵션을 지정해 비트맵 생성
val option = BitmapFactory.Options()
option.inSampleSize = 4
val bitmap = BitmapFactory.decodeStream(inputStream, null, option)
갤러리 앱 연동 방법
// 사진 목록 출력
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
intent.type = "image/*"
requestGalleryLauncher.launch(intent)
- 이미지 정보를 얻어 실제 화면에 출력되는 크기와 비교해서 inSampleSize 값을 계산
// 적절한 비율로 이미지 크기 줄이기
private fun calculateInSampleSize(fileUri: Uri, reqWidth: Int, reqHeight: Int): Int {
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
try {
var inputStream = contentResolver.openInputStream(fileUri)
BitmapFactory.decodeStream(inputStream, null, options)
inputStream!!.close()
inputStream = null
} catch (e: Exception) {
e.printStackTrace()
}
val (height: Int, width: Int) = options.run { outHeight to outWidth}
var inSampleSize = 1
// inSampleSize 비율 계산
if (height > reqHeight || width > reqWidth) {
val halfHeight: Int = height / 2
val halfWidth: Int = width / 2
while (halfHeight / inSampleSize >= reqHeight &&
halfWidth / inSampleSize >= reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
// 이미지를 불러오는 코드
requestGalleryLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult())
{
try {
// inSampleSize 비율 계산, 지정
val calRatio = calculateInSampleSize(it!!.data!!.data!!,
resources.getDimensionPixelSize(R.dimen.imgSize),
resources.getDimensionPixelSize(R.dimen.imgSize))
val option = BitmapFactory.Options()
option.inSampleSize = calRatio
// 이미지 로딩
var inputStream = contentResolver.openInputStream(it!!.data!!.data!!)
val bitmap = BitmapFactory.decodeStream(inputStream, null, option)
inputStream!!.close()
inputStream = null
bitmap?.let {
binding.galleryResult.setImageBitmap(bitmap)
} ?: let {
Log.d("kim", "bitmap null")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
카메라 앱 연동하기
카메라 앱을 연동하여 사진을 촬영하고 그 결과를 돌려받는 2가지 방법
- 사진 데이터를 가져오는 방법 (사진 데이터의 크기가 작다는 단점)
- 사진 파일을 공유하는 방법
사진 데이터를 가져오는 방법
인텐트로 카메라 앱의 사진 촬영 액티비티를 실행
// 사진 촬영 액티비티 실행
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
requestCameraThumbnailLauncher.launch(intent)
카메라 앱에서 넘어온 사진 데이터는 ActivityResult Callback에서 획득
// 사진 데이터 가져오기
requestCameraThumbnailLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult())
{
val bitmap = it?.data?.extras?.get("data") as Bitmap
}
사진 파일을 공유하는 방법
- 앱에서 사진을 저장할 파일을 만듭니다.
- 사진 파일 정보를 포함한 인텐트를 전달해 카메라 앱을 실행합니다.
- 카메라 앱으로 사진을 촬영하여 공유된 파일에 저장합니다.
- 카메라 앱을 종료하면서 성공 또는 실패를 반환합니다.
- 카메라 앱이 저장한 사진 파일을 앱에서 이용합니다.
- 사진 파일을 공유하는 방법을 이용하려면 먼저 앱에서 외장 메모리에 파일을 생성
- getExternalStoragePublicDirectory( ) 또는 getExternal FilesDir( ) 함수를 이용
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- API 레벨 24 버전부터는 file:// 프로토콜로 구성된 URI를 외부에 노출하지 못함 (엄격 모드 적용)
- 앱끼리 파일을 공유하려면 content// 프로토콜을 이용하고 이 URI에 임시로 접근할 수 있는 권한을 부여
- FileProvider 클래스는 androidx 라이브러리에서 제공하며 XML 설정을 기반으로 해서 content:// 프로토콜로 구성된 URI를 생성해 줍니다.
<!-- 파일 프로바이더용 XML 파일 -->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="myfiles" path = "Android/data/com.example.test16/files/Pictures" />
</paths>
- 파일 프로바이더용 XML 파일을 매니페스트 파일에 등록
<provider
android:authorities="com.example.test16.fileprovider"
android:name="androidx.core.content.FileProvider"
android:exported="true"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
- 파일 생성
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val storageDir: File? = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
val file = File.createTempFile(
"JPEG_${timeStamp}_",
".jpg",
storageDir
)
filePath = file.absolutePath
- FileProvider를 이용해 Uri 객체를 만들고 이를 카메라 앱을 실행하는 인텐트의 엑스트라 데이터로 설정
val photoURI: Uri = FileProvider.getUriForFile(
this,
"com.example.test16.fileprovider", file
)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
requestCameraFileLauncher.launch(intent)
- 카메라 앱에서 사진을 촬영한 후 다시 앱으로 돌아왔을 때 실행되는 코드
// 비트맵 이미지 생성
requestCameraFileLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult())
{
val option = BitmapFactory.Options()
option.inSampleSize = 10
val bitmap = BitmapFactory.decodeFile(filePath, option)
bitmap?.let {
binding.cameraFileResult.setImageBitmap(bitmap)
}
}
지도 앱 연동하기
// 지도 앱을 실행하는 인텐트
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("geo: 37.5662952, 12639779451"))
startActivity(intent)
전화 앱 연동하기
<uses-permission android:name="android.permission.CALL_PHONE" />
// 전화 앱을 실행하는 인텐트
val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:02-120"))
startActivity(intent)
'안드로이드' 카테고리의 다른 글
스레드 기반 작업의 한계, Coroutine Dispatcher (0) | 2025.01.06 |
---|---|
[Android] Ktlint적용하기 (0) | 2024.10.29 |
[Android | Kotlin] 콘텐츠 프로바이더 이해하기 (0) | 2024.01.03 |
[Android | Kotlin] 잡 스케줄러 (1) | 2023.12.31 |
[Android | Kotlin] 백그라운드 제약 (0) | 2023.12.31 |