728x90

위험권한을 편리하게 체크해주는 tedpermission 라이브러리를 코틀린으로 변환한 것과 뒤로 가기를 두번 연속 누르면 종료되는 함수를 적어둔다.

구글지도를 간단하게 구현할 목적이라 dependencies에 구글 라이브러리가 추가되어 있다.

 

앱 build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.0"

    defaultConfig {
        applicationId "com.link2me.android.googlemap"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }

}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    implementation 'com.google.android.gms:play-services-maps:17.0.0'
    implementation 'com.google.android.gms:play-services-location:17.0.0'
    implementation 'gun0912.ted:tedpermission:2.0.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.android.material:material:1.1.0'

}

2021.7월 확인 사항

implementation 'io.github.ParkSangGwon:tedpermission:2.3.0' 로 변경되었더라.

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.link2me.android.googlemap">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <!-- 도시 블록 내에서 정확한 위치(네트워크 위치) -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <!-- 정확한 위치 확보(네트워크 위치 + GPS 위치) -->

    <application
        android:allowBackup="false"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
        <activity android:name=".MapsActivity"></activity>
        <activity
            android:name=".SplashActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"
                tools:replace="android:resource" />
        </provider>
    </application>

</manifest>

 

SplashActivity.kt

import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.gun0912.tedpermission.PermissionListener
import com.gun0912.tedpermission.TedPermission

class SplashActivity : AppCompatActivity() {
    var mContext: Context? = null
    private val SPLASH_TIME_OUT: Long = 2000 // 2 sec

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mContext = this@SplashActivity;
        checkPermissions()
    }

    var permissionlistener: PermissionListener = object : PermissionListener {
        override fun onPermissionGranted() {
            initView()
        }

        override fun onPermissionDenied(deniedPermissions: MutableList<String?>?) {
            Toast.makeText(
                this@SplashActivity,
                "권한 허용을 하지 않으면 서비스를 이용할 수 없습니다.",
                Toast.LENGTH_SHORT
            ).show()
        }
    }

    private fun checkPermissions() {
        if (Build.VERSION.SDK_INT >= 26) { // 출처를 알 수 없는 앱 설정 화면 띄우기
            val pm: PackageManager = mContext!!.getPackageManager()
            Log.e("PackageName", packageName)
            if (!pm.canRequestPackageInstalls()) {
                startActivity(
                    Intent(
                        Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
                        Uri.parse("package:$packageName")
                    )
                )
            }
        }
        if (Build.VERSION.SDK_INT >= 23) { // 마시멜로(안드로이드 6.0) 이상 권한 체크
            TedPermission.with(mContext)
                .setPermissionListener(permissionlistener)
                .setRationaleMessage("앱을 이용하기 위해서는 접근 권한이 필요합니다")
                .setDeniedMessage("앱에서 요구하는 권한설정이 필요합니다...\n [설정] > [권한] 에서 사용으로 활성화해주세요.")
                .setPermissions(
                    Manifest.permission.ACCESS_FINE_LOCATION,
                    Manifest.permission.ACCESS_COARSE_LOCATION
                )
                .check()
        } else {
            initView()
        }
    }

    private fun initView() {
        Handler().postDelayed({
            startActivity(Intent(this, MapsActivity::class.java))
            finish()  // close this activity
        }, SPLASH_TIME_OUT)
    }

}

 

import android.app.Activity
import android.os.Build
import android.widget.Toast

class BackPressHandler(private val activity: Activity) {
    private var backKeyPressedTime: Long = 0
    private var toast: Toast? = null
    fun onBackPressed() {
        if (isAfter2Seconds) {
            backKeyPressedTime = System.currentTimeMillis()
            // 현재시간을 다시 초기화
            toast = Toast.makeText(
                activity,
                "\'뒤로\'버튼을 한번 더 누르면 종료됩니다.",
                Toast.LENGTH_SHORT
            )
            toast!!.show()
            return
        }
        if (isBefore2Seconds) {
            appShutdown()
            toast!!.cancel()
        }
    }

    // 2초 지났을 경우
    private val isAfter2Seconds: Boolean
        private get() = System.currentTimeMillis() > backKeyPressedTime + 2000

    // 2초가 지나지 않았을 경우
    private val isBefore2Seconds: Boolean
        private get() = System.currentTimeMillis() <= backKeyPressedTime + 2000

    private fun appShutdown() {
        // 홈버튼 길게 누르면 나타나는 히스토리에도 남아있지 않고 어플 종료
        if (Build.VERSION.SDK_INT >= 21) activity.finishAndRemoveTask() else activity.finish()
        System.exit(0)
    }
}

 

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity

class MapsActivity : AppCompatActivity() {
    private var backPressHandler: BackPressHandler? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)

        backPressHandler = BackPressHandler(this); // 뒤로 가기 버튼 이벤트
    }

    override fun onBackPressed() {
        backPressHandler!!.onBackPressed()
    }
}

 

var a = readLine()?.capitalize()
// ?. : 안전 호출 연산자


var a = readLine()!!.capitailize()
// !! : non-null 단언 연산자. null이 될 수 없다는 것을 단언하는 연산자다.

 

블로그 이미지

Link2Me

,