728x90

Java 코드와 Kotlin 코드를 혼용하여 작성하는 환경 설정이 Android Studio 가 버전 업 되면서 변경되었다.

https://developer.android.com/kotlin/add-kotlin?hl=ko 이 URL을 참조하면 최신으로 변경된 것을 확인할 수 있다.

 

코틀린 최신 버전이 1.7.10 이지만 1.6.20 으로 설정했다.

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = '1.6.20'
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
 
plugins {
    id 'com.android.application' version '7.2.2' apply false
    id 'com.android.library' version '7.2.2' apply false
}
 
 
task clean(type: Delete) {
    delete rootProject.buildDir
}

 

app build.gradle

plugins {
    id 'com.android.application'
    // 코틀린 혼용 사용을 위해 추가
    id 'kotlin-android'
    id 'kotlin-parcelize'
    id 'kotlin-kapt'
    // id 'kotlin-android-extensions' // deprecated 되었음.
}
 
android {
    compileSdk 32
 
    defaultConfig {
        applicationId "com.link2me.android.retrofit_mvvm_login"
        minSdk 23
        targetSdk 32
        versionCode 1
        versionName "1.1"
    }
 
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
 
    // View Binding : Android Studio 4.0 이상
    buildFeatures {
        viewBinding = true
    }
}
 
dependencies {
    // 아래 2줄은 코틀린 혼용 사용을 위해 추가
    implementation 'androidx.core:core-ktx:1.8.0' // 2022년 6월 1일 버전
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
 
    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
 
//    implementation 'gun0912.ted:tedpermission:2.0.0'  // 위험권한 퍼미션 처리
    implementation 'io.github.ParkSangGwon:tedpermission-normal:3.3.0' // 위험권한 퍼미션 처리
    implementation 'androidx.cardview:cardview:1.0.0'  // 레이아웃으로 사용할 CardView
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
 
    implementation 'androidx.navigation:navigation-fragment:2.1.0'
    implementation 'androidx.navigation:navigation-ui:2.1.0'
 
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.9.0'
 
    def lifecycle_version = "2.5.0"
    // ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
    // lifecycle-extensions의 API는 지원 중단되었다.
 
    // 이미지 출력용 Glide
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    //annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    kapt 'com.github.bumptech.glide:compiler:4.11.0' // Kotlin plugin doesn't pick up annotationProcessor dependencies
}

 

 

 

 

블로그 이미지

Link2Me

,
728x90

세부사항은 https://developer.android.com/about/versions/12/behavior-changes-12?hl=ko

 

동작 변경사항: Android 12를 타겟팅하는 앱  |  Android Developers

모든 앱에 영향을 주는 Android 12의 변경사항을 알아봅니다.

developer.android.com

를 읽어보면 된다.

 

앱이 Android 12 이상을 타겟팅하고 인텐트 필터를 사용하는 활동이나 서비스, broadcast receiver를 포함하면 이러한 앱 구성요소의 android:exported 속성을 명시적으로 선언해야 한다.

<service android:name="com.example.app.backgroundService"
         android:exported="false">
    <intent-filter>
        <action android:name="com.example.app.START_BACKGROUND" />
    </intent-filter>
</service>

 

android:exported
- 앱의 활동에 인텐트 필터가 포함되면 다른 앱에서 Activity를 시작할 수 있도록 이 요소를 'true'로 설정해야 한다.
- 모든 앱에서 Activity에 액세스할 수 있으며 정확한 클래스 이름으로 활동을 시작할 수 있다.
- 인텐트 필터가 없는 경우의 기본값은 false 이다.
- 같은 애플리케이션의 구성요소나 사용자 ID가 같은 애플리케이션, 권한있는 시스템 구성요소에서만 시작될 수 있다.

 

앱 build.gradle

apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 31
    defaultConfig {
        applicationId "com.spectrum.android.ping"
        minSdkVersion 23
        targetSdkVersion 31
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
 
dependencies {
    implementation project(':lib')
}

 

오래된 앱을 targetSdkVersion 31 로 업데이트하면 아래와 같은 에러가 발생한다.

 

아래와 같이 수정되면 OK

Android 10 이라도 targetSdkVersion 31로 하면 android:exported="true" 설정해야 동작된다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.spectrum.android.ping">
 
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        >
        <activity android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>
 

 

블로그 이미지

Link2Me

,
728x90

Android Studio 에서 업그레이드하라는 문구 메시지가 나온다.

너무 최신버전으로 업그레이드를 하지 않고 적당한 버전으로 업그레이드를 하려고 했더니 쉽지 않다.

 

처음에 설치된 버전은 Project build.gradle 에서 확인하면 4.1.1 버전이었다.

2021년도에 7.0.2 버전으로의 업그레이드를 한 기억이 있어서 수작업으로 7.0.2 버전으로 설정을 했더니 잘 안된다.

 

 

gradle-wrapper.properties 에서 수작업으로 아래와 같이 수정을 해주었더니 진행이 된다.

 

에러 메시지가 나온다.

 

에러 메시지를 무시하고 해도 되는데 없애는 방법을 적어둔다.

 

이렇게 했음에도 최신버전으로 업그레이드를 하라는 문구는 나오는데 무시했다.

7.1.0 버전으로 코드 작성을 해 본 적이 없어서 무엇을 또 수정해야 할지 몰라서다.

블로그 이미지

Link2Me

,
728x90

오랫만에 Android Studio 를 구동시켰더니 classpath "com.android.tools.build:gradle:7.0.0" 로 업데이트되고 

JDK 11 버전으로 설치를 하라고 나온다.

https://www.oracle.com/java/technologies/javase-jdk11-downloads.html

에서 파일을 다운로드 받아서 설치한다.

 

 

 

Android Studio 에서 설정을 변경한다.

 

앱 build.gradle

plugins {
    id 'com.android.application'
    id 'kotlin-android'
}
 
android {
    compileSdk 30
 
    defaultConfig {
        applicationId "com.link2me.android.bdmap"
        minSdk 26
        targetSdk 30
        versionCode 1
        versionName "1.0"
    }
 
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}
 
dependencies {
    implementation 'androidx.core:core-ktx:1.6.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
}

gradle:7.0.0 에 맞게 라이브러리를 변경해주지 않는 것은 동작되지 않는 것도 있더라.

구글 검색을 해서 변경된 라이브러리에 맞게 수정해주니 제대로 동작된다.

 

project gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    ext.kotlin_version = '1.5.20'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.0"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
 
task clean(type: Delete) {
    delete rootProject.buildDir
}
 

 

settings.gradle

기존에는 프로젝트 그래들에 있었던 사항이 이제는 settings.gradle에 추가해야 정상 동작하더라.

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url "https://naver.jfrog.io/artifactory/maven/" }
        maven { url "https://jitpack.io" }
        maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' }
 
    }
}
rootProject.name = "BDMAP"
include ':app'
include ':gnbdmap'
 

 

 

블로그 이미지

Link2Me

,
728x90

Handler 코드를 아래와 같이 수정해야 제대로 동작된다.

Java  Handler handler = new Handler(Looper.getMainLooper());
kotlin  val handler = Handler(Looper.getMainLooper())

 

다른 앱 호출 및 실행

https://developer.android.com/training/basics/intents/package-visibility?hl=ko 참조(패키지 공개상태 관리)

안드로이드 11 에서 QUERY_ALL_PACKAGES 권한이 도입되었다.

간단하게 아래 한줄을 추가해주면 어플에서 내비 등을 호출할 때 이상없이 동작된다.

<!-- 다른 앱 실행 : SDKVersion 30 이상은 권한 추가 필요 -->
<permission android:name="android.permission.QUERY_ALL_PACKAGES" />

 

지정한 특정 앱만 실행하도록 하는 것은

<queries>
    <package android:name="kt.navi" />
    <package android:name="com.locnall.KimGiSa" />
    <package android:name="com.nhn.android.nmap" />
</queries>

<?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.map">
 
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <!-- 다른 앱 실행 : SDKVersion 30 이상은 권한 추가 필요 -->
    <permission android:name="android.permission.QUERY_ALL_PACKAGES" />
 
    <queries>
        <intent>
            <action android:name="android.intent.action.MAIN" />
        </intent>
    </queries>
 
    <queries>
        <package android:name="kt.navi" />
        <package android:name="com.locnall.KimGiSa" />
        <package android:name="com.nhn.android.nmap" />
    </queries>
 
    <application
        android:name=".GlobalApplication"
        android:allowBackup="true"
        android:extractNativeLibs="true"
        android:icon="@drawable/map_icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:usesCleartextTraffic="true">
 
 
        <meta-data
            android:name="com.naver.maps.map.CLIENT_ID"
            android:value="@string/naver_app_key" />
        <meta-data
            android:name="com.kakao.sdk.AppKey"
            android:value="@string/kakao_app_key" />
    </application>
 
</manifest>

 

참고하면 좋은 글 : https://codechacha.com/ko/android11-package-visibility/

 

블로그 이미지

Link2Me

,
728x90

ADB를 활용한 스마트폰 원격 연결방법

 

1. 먼저 PC와 스마트폰간에 USB 케이블로 연결한다.

2. CMD 콘솔창을 띄워서

   adb tcpip 9000    // 임의의 포트 설정

 

3. 스마트폰의 Wi-Fi 를 활성화 시킨다.

4. 스마트폰의 사설 IP주소를 알 수 있게 앱 스토어에서 WiFi Analyzer 앱을 설치한다.

   앱을 실행하면 사설 IP주소를 확인할 수 있다.

   다른 방법으로는 IPTime 공유기에서 확인할 수도 있다.

 

제 스마트폰의 접속 IP주소를 확인해보니 192.168.1.13 이 잡혀 있다.

 

5. adb connect [스마트폰의 연결된 와이파이 ip주소]:[위에서 지정한 포트번호]

    adb connect 192.168.1.13:9000

   

 

연결 해제시에는 adb disconnect 를 하면 된다.

 

 

블로그 이미지

Link2Me

,
728x90


ADB(Android Debug Bridge)는 PC/노트북에서 안드로이드 단말로 명령을 내릴 수 있게 도와주는 도구이다.


1. usb 디버깅 허용 후 단말을 PC와 연결한다.

2. CMD 창에서 아래 명령어들을 입력한다.


ㅇ에뮬레이터 또는 단말 연결을 확인하는 명령어 : adb devies


ㅇ 안드로이드 버전 확인 : adb shell getprop ro.build.version.release


ㅇ 단말 재부팅 : adb reboot


ㅇ APK 설치 : adb install -r [파일명].apk


ㅇ APK 삭제 : adb uninstall [패키지명]




ADB PATH 설정 방법


윈도우 CMD 창을 열고 adb.exe 를 실행해본다.

명령이 실행되지 않으니 adb.exe 경로를 찾아서 윈도우 시스템 환경변수에 등록을 해야 한다.


윈도우키 + Pause 키를 누르면 ....





여기까지 하고 확인 확인으로 창을 닫아주면 PATH 설정은 완료되었다.


이제 CMD 창에서 다시 adb 명령어를 실행해보자.

아래와 같은 화면이 출력되면 PATH 설정이 완료된 것이다.


안드로이드 스튜디오에서도 명령이 잘되는지 실행해 보자.

만약 실행이 안된다면 안드로이드 스튜디오를 재실행하면 될 것이다.


블로그 이미지

Link2Me

,
728x90

Oracle에서 제공하는 JAVA 가 무료라서 많이 사용했는데, 기업 등에서는 라이선스 비용을 지불해야 하는 문제가 있어서 집에서 사용하는 것이기는 하지만 무료로 사용할 수 있는 Open JDK 를 설치해 보기로 했다.


Open JDK 파일 다운로드 : https://www.azul.com/downloads/

다운로드 받은 설치파일을 실행한다.





환경변수 등록

Open JDK 실행 경로 환경 변수 추가는 고급 시스템 설정을 통해 지정할 수 있다.

먼저 Windows 키 + Pause 키를 누른다.


JAVA_HOME 에 대한 변수 설정을 한다.




맨 위에 이미 등록되어 있는데, 9번과 같이 추가해본다. 그리고 맨 윗줄은 지웠다.


이제 설치 여부를 CMD 창에서 확인한다.

 "java -version" 명령을 실행하여 자바 실행 파일이 정상적으로 실행되는지 확인한다.


이제 Open JDK를 설치하는 모든 과정이 완료되었다.

블로그 이미지

Link2Me

,
728x90

맨날 Debugging을 Log 찍어가면서 해왔는데, 우연히 검색해보다 페이스북에서 내놓은 Stetho 라이브러리를 이용하면 편하게 디버깅할 수 있다는 걸 알아서 사용해보고 간략하게 적어둔다.

 

https://github.com/facebook/stetho 에 가면 최신버전을 알 수 있다.

 

앱 build.gradle 추가

 

 

AndroidManifest.xml 추가

를 추가한다.

 

 

MyApplication Class 추가

public class MyApplication extends Application {
  public void onCreate() {
    super.onCreate();
    Stetho.initializeWithDefaults(this);
  }
} 

 

 

여기까지 하고 나서 앱을 컴파일 하면 연결된 폰의 정보를 크롬브라우저에서 확인할 수 있다.

 

크롬 주소창에 chrome://inspect 라고 입력한다.

아래와 같이 연결된 삼성폰 정보가 보이고 앱 명칭이 보인다.

 

 

2번을 누르면 새로운 창이 뜬다.

 

SharedPreference 정보를 살펴보니 저장된 정보가 보인다.

테스트 목적으로 만드는 템플릿 형식의 앱 개발이라 정보는 보여줘도 무방하기에 그대로 보이도록 했다.

PIN 인증번호 6자리 입력한 정보가 그대로 보인다.

 

여기서 직접 정보를 수정할 수도 있다.

 

PIN 번호도 임의변경하고 기존 PIN번호로 인증 시도했더니 안된다. 변경 PIN 번호 입력해야 가능하다.

이름과 서버에서 가져오는 이미지 저장 idx 값을 임의로 1에서 2로 변경해보고 이름도 홍길동으로 변경해봤다.

 

 

SQLite도 adb shell로 들어가서 확인하거나, db 파일 추출해서 pc에서 확인할 필요없이,
SQL을 직접 날려가며 확인할 수 있다고 하는데 SQLite DB 코드 만들면 테스트 해봐야겠다.

 

Network 연결방식은 Volley 라이브러리를 사용해서 그런지 정보가 안보인다.

Retrofit2 라이브러리를 사용한 코드로 테스트 해보면 제대로 보이려나?

'안드로이드 > Android Studio' 카테고리의 다른 글

ADB(Android Debug Bridge)  (0) 2021.01.07
OpenJDK 설치  (0) 2020.11.08
android SDK 설치 위치 변경  (0) 2020.07.06
[코틀린] Anko 라이브러리 추가 방법  (0) 2020.04.20
자바와 코틀린 함께 사용하기  (0) 2020.03.22
블로그 이미지

Link2Me

,
728x90

개발툴 설치를 기본으로 설치하지 않고 내가 원하는 디렉토리를 지정하여 설치할 수 있다.



이렇게 필요한 것을 설치하면 된다.

블로그 이미지

Link2Me

,
728x90

Anko 라이브러리에 대한 사항은 https://github.com/Kotlin/anko 를 참조한다.


Anko Commons은 안드로이드 애플리케이션을 작성할 때 일반적으로 자주 구현하는 기능을 간편하게 추가할 수 있는 유틸리티 함수를 제공한다.

- AnKo Commons : 인텐트, 다이얼로그, 로그 등을 편리하게 사용하는 라이브러리
- AnKo Layouts : 안드로이드 레이아웃을 코드로 쉽게 작성하는 라이브러리
- AnKo SQLite : SQLite를 쉽게 사용하는 라이브러리
- AnKo Coroutines : 코루틴을 쉽게 사용하는 라이브러리


Project build.grade 추가사항

buildscript {
    ext.kotlin_version = '1.3.72'
    ext.anko_version = '0.10.8'

    repositories {
        google()
        jcenter()
       
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.3'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
} 


앱 build.gradle 추가사항

한번에 Anko 가 제공하는 모든 기능을 포함하고자 한다면 (including Commons, Layouts, SQLite)

dependencies {
    implementation "org.jetbrains.anko:anko:$anko_version"
}
 


dependencies {
    // Anko Commons
    implementation "org.jetbrains.anko:anko-commons:$anko_version"
}

블로그 이미지

Link2Me

,
728x90

Java 로 코딩된 프로젝트에 코틀린 코드 일부를 추가하는 걸 테스트 해보고 간단하게 적어둔다.


프로젝트 build.gradle

buildscript {
    ext.kotlin_version = '1.3.71'
    repositories {
        google()
        jcenter()
       
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}


앱 build.gradle

apply plugin: 'com.android.application'
// 코틀린 혼용 사용을 위해 추가
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.link2me.android.javakotlin"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

    }

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

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // 코틀린 혼용 사용을 위해 추가
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.annotation:annotation:1.1.0'

    implementation 'com.google.android.material:material:1.0.0'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'gun0912.ted:tedpermission:2.0.0'

    implementation 'com.squareup.retrofit2:retrofit:2.7.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.7.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
}


Java 코드 파일과 kotlin 코드 파일을 혼용하여 사용해봤는데 잘 동작하는 걸 확인할 수 있었다.

코틀린을 완벽하게 이해한 상태이면 Java 코드 필요없겠지만 코틀린 문법 공부 하다 말아서 이렇게라도 해보는 것이 의의가 있다.


블로그 이미지

Link2Me

,
728x90
전세계적으로 개발자가 자바 언어만큼 많이 사용하는 또다른 프로그램 개발 언어는 C언어와 C++언이이다.
C/C++언어는 자바와 달리 특정 플랫폼에 최적화시킬 수 있는 장점을 제공한다.
java만 사용하여 필요 기능과 성능을 모두 만족시키기는 힘들다. 안드로이드는 자바 기반의 언어다. 자바는 JVM(Java Virtual Machine)에서 동작하기 때문에 실제적인 디바이스에 접근이 불가능하다. 그래서 나온 것이 안드로이드 NDK이다.
NDK을 사용하여 디바이스에 접근 제어할 수 있는 C/C++ 함수들을 호출할 수 있도록 하여 안드로이드 개발자들이 좀 더 효율성 있게 개발할 수 있도록 도와주는 역할을 한다.

C, C++ 로 작성된 프로그램을 안드로이드에서 사용할 수 있도록 JDK에서 제공하는 것이 JNI(Java Native Interface) 이다.

Java에는 상응하는 것이 없는 수많은 C/C++ 라이브러리가 있다. 이러한 라이브러리를 이용하려면 NDK를 사용하는 것이 좋다.

안드로이드는 C/C++언어로 개발된 프로그램을 Java와 구분하기 위해 네이티브 코드라고 하며, 네이티브 코드로 작성되어 실행이 가능한 메소드를 일반 Java 메소드와 구분하여 네이티브 함수라 부른다.


안드로이드 스튜디오에서 C++ 코드를 import 하여 사용하기 위해 필요한 설정이다.

화면 캡처는 맥북에서 했다. 맥 윈도우 8.1 에서 CMake 인식이 안되어서 맥북 모드로 다시 확인하니까 맥북에서는 잘 인식되어 installed 했다.

최신 알파버전 Android Studio 4.0  을 다른 폴더에 설치하고 실행해서 보니 안보이던 cmake 선택창이 보여서 설치했더니, 이제는 Android Studio 3.5.2 에서도 잘 보인다. 흐미....



https://developer.android.com/ndk/guides?hl=ko 에 설명이 잘 되어 있다.

NDK(Native Development Kit)는 Android에서 C 및 C++ 코드를 사용할 수 있게 해주는 일련의 도구 모음으로, 네이티브 액티비티를 관리하고 센서 및 터치 입력과 같은 물리적 기기 구성요소에 액세스하는 데 사용할 수 있는 플랫폼 라이브러리를 제공한다.

- 기기에서 최대한의 성능을 도출하여 짧은 지연 시간을 달성해야 하는 경우

- 게임 또는 물리학 시뮬레이션과 같은 연산 집약적인 애플리케이션을 실행하는 경우

- 본인 또는 다른 개발자의 C 또는 C++ 라이브러리를 재사용하는 경우


ㅇCMake: Gradle과 함께 작동하여 네이티브 라이브러리를 빌드하는 외부 빌드 도구다.

   (Android Studio’s default build tool for native libraries is CMake.)

   ndk-build만 사용하려는 경우에는 이 구성요소가 필요하지 않다.

  

ㅇLLDB: Android 스튜디오에서 네이티브 코드를 디버깅하는 데 사용하는 디버거다.



C++ 코드 사용 가능한 프로젝트 생성




설치된 폴더를 확인해보면, NDKTest 라는 프로젝트명이 생겼다.


소스 폴더에 java, res 폴더 외에 cpp 라는 폴더가 추가로 생긴 걸 확인할 수 있다.


cpp 폴더안에 native-lib.cpp 파일과 CMakeLists.txt 파일 기본 생성되었다.


모든 C++ 파일과 라이브러리는 cpp 폴더 안에 있어야 한다.


cpp 파일 작성법

default 로 생성된 파일을 분석해보자.

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_link2me_android_ndktest_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}


#include <jni.h> // 다수의 매크로 정의, 타입, 구조체, 함수를 포함하는 헤더 파일로 반드시 포함해야 한다.

JNI(Java Native Interface)를 통해 접근할 수 있는 C++ 함수명은 다음과 같은 형태여야 한다.

'JNIEXPORT <함수 타입> JNICALL Java_<패키지 명>_<클래스 명>_<함수명>(JNIEnv*, jobject, 파라미터) 이다.

Java_com_link2me_android_ndktest_MainActivity_stringFromJNI(JNIEnv *env, jobject) {

Java는 접두어이고,

package="com.link2me.android.ndktest" 패키지명에서 . 대신에 _ 로 바꾼다.

자바 클래스명 : MainActivity

함수명 : stringFromJNI

JNIEnv*, jobject는 네이티브에서 자바로 접근하는 포인트가 된다.


extern "C" JNIEXPORT jstring JNICALL
Java_com_link2me_android_ndktest_MainActivity_intFromJNI(
        JNIEnv *env, jobject b, jint a, jint b) {
    // 연산결과 = 연산식
    return env->NewStringUTF(연산결과);
}


public native int sum(int a, int b);

매개변수가 추가된 경우에는 네이티브 코드에 자주색처럼 추가해주면 된다.



MainActivity.java 파일 추가 사항을 살펴보자.

public class MainActivity extends AppCompatActivity {

    // 네이티브 함수를 사용하기 위하여 동적 라이브러리를 로딩
    // 동적라이브러리는 stringFromJNI메서드가 호출되기 전에 로딩되어야 하므로 static으로 초기화
    static {
        System.loadLibrary("native-lib"); // 라이브러리명은 소문자를 사용해야 한다.
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    // java에서 사용할 네이티브 함수의 선언
    // native라는 키워드는 이 메서드가 java가 아닌 다른 언어로 작성된 것임을 암시
    public native String stringFromJNI();
}

자바 프로그램내 선언한 메소드에 native 라는 키워드를 추가하지 않는다면, 자바 컴파일러는 메소드들이 모두 자바 언어로 작성되어 있다고 가정한다.

native 선언은 메소드는 자바 언어가 아닌 C나 C++ 언어로 작성되어 있다는 사실을 알려준다.

자바 프로그램의 특성상 메소드의 선언은 C/C++ 언어와 달리 클래스의 어디에 위치해도 좋다.

네이티브 메소드는 커널에 의해 실행되기 때문에 자바 가상 머신에서 관리하지 않는다.

자바를 실행시키는 가상머신은 기본적으로 모든 문자열을 UTF-16 이라는 유니코드(Unicode)로 처리한다.


앱 build.gradle

cpp가 포함되지 않은 앱 build.gradle 에 비해 자주색으로 표시된 부분이 추가되어 있다.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.link2me.android.ndktest"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
}


참고자료

https://programmingfbf7290.tistory.com/entry/NDK2-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4-NDK-JNI-%EA%B8%B0%EB%B3%B8-%EC%98%88%EC%A0%9C?category=666988


참고하면 좋은 책 : 안드로이드 C-C++ 프로그래밍

블로그 이미지

Link2Me

,
728x90

http://www.jcraft.com/jsch/ 사이트에서 파일을 다운로드 받는다.



다운로드 받은 파일을 libs 폴더에 복사/이동한다.


앱 build.gradle 에 추가한다.


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'gun0912.ted:tedpermission:2.0.0'
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.google.android.material:material:1.0.0'
    implementation files('libs/jsch-0.1.55.jar')

}


Sync Now 를 해주면 라이브러리 추가가 완료된다.

블로그 이미지

Link2Me

,
728x90

Android Studio 에서 타이틀 바가 안나오게 하는 방법은 두가지가 있다.

values 폴더 밑에 styles.xml 파일을 수정한다.


방법 1.

styles.xml 파일을 아래와 같이 수정한다.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources> 


방법2.

styles.xml 파일을 아래와 같이 수정한다.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

</resources>


AndroidManifest.xml 파일 수정사항

    <application
        android:allowBackup="false"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme.NoActionBar">
 



두번째 방법이 손 댈 곳이 좀 더 많다.

블로그 이미지

Link2Me

,
728x90

Android 앱을 개발한 후 배포를 하기 위해 알아야 할 사항이다.


앱 build.gradle 에서

    defaultConfig {
        applicationId "com.android.USBController"
        minSdkVersion 19
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"


모든 Android 앱은 저마다 com.example.myapp과 같이 자바 패키지 이름처럼 보이는 고유한 애플리케이션 ID가 있다.
이 ID 덕분에 기기와 Google Play Store에서 각각의 앱을 고유하게 식별할 수 있는 것이다.
앱의 새로운 버전을 업로드하려면 애플리케이션 ID와 로그인할 때 사용할 인증서가 원래의 APK와 같아야 한다.
애플리케이션 ID를 변경할 경우 Google Play Store에서는 APK를 완전히 다른 앱으로 취급하게 된다.
따라서 일단 앱을 게시한 후에는 절대로 애플리케이션 ID를 변경하지 마시라.

앱을 개발할 때 기능을 약간 다르게 비교하면서 개발할 경우 applicationId 인 com.android.USBController 를 같게 하면 동일한 앱으로 컴파일된다는 걸 알 수 있다.
이 applicationId 만 다르게 하여 컴파일하면 두개의 앱이 생성되는 걸 확인할 수 있을 것이다.

PlayStore에 등록된 앱은 VersionCode와 VersionName의 두가지 속성을 가지고 있다.

VersionCode는 정수값을 이용하는데, 플레이 스토어 내부적으로 상위 버전을 구분하는데 사용되고, VersionName은 플레이 스토어에서 사용자에게 보여주기 위한 값으로 사용된다.


versionCode : 정수이며, 내부 버전 번호로 사용된다.
하나의 버전이 다른 버전보다 최신인지 여부를 판단하는 데만 사용되며, 번호가 높을수록 최신 버전이다.


versionName : 문자열이며, 사용자에게 표시되는 버전 번호로 사용된다.
사용자에게 표시하는 것 이외에 다른 용도는 없다.
따라서 별도로 시스템상으로 강제하고 있지 않다.


기업 내부용으로 이용시에는 신뢰할 수 없는 앱이라는 경고 표시가 나온다.

앱을 새롭게 업데이트해서 배포할 때마다

versionCode 와 versionName 을 숫자를 증가시켜야 오류가 발생하지 않는다.


아래 코드는 앱에서 현재 사용하는 버전이 어떤 버전인지 UI상에 표시해주는 코드이다.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_menu);
        mContext = this.getBaseContext();
        backPressHandler = new BackPressHandler(this); // 뒤로 가기 버튼 이벤트

        // type1이 버튼형식
        findViewById(R.id.menu1).setOnClickListener(this);
        findViewById(R.id.menu2).setOnClickListener(this);
        findViewById(R.id.menu3).setOnClickListener(this);
        findViewById(R.id.menu4).setOnClickListener(this);

        TextView tv_version = findViewById(R.id.version);

        PackageInfo pInfo = null;
        try {
            pInfo = getPackageManager().getPackageInfo(this.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        int versionCode = pInfo.versionCode;
        String versionName = pInfo.versionName; // build.gradle 에 기록된 VersionName
        tv_version.setText("Version "+versionName);
    }


블로그 이미지

Link2Me

,
728x90

파일 구조를 분리하면서 AndroidManifest.xml 파일을 다음과 같이 했더니 파일이 두개가 설치되는 문제점이 있다.


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

    <uses-feature android:name="android.hardware.usb.host" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>

            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
        </activity>
        <activity android:name=".Setting" />
        <activity android:name=".ShortKey" />
        <activity android:name=".Upgrade" />
    </application>

</manifest>
 


시작되는 파일을 변경처리 했더니 위와 같이

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
부분이 두개가 생겼는데 그냥 컴파일 했더니 파일이 두개가 생긴다.

반드시 하나를 지워줘야 한다.

그래서 MainActivity 부분에 있는 걸 지워줬다.

이유는 위험권한 체크하는 부분을 Intro 로 옮겼는데 Intro 부분걸 지우면 권한 체크를 하지 못한다.

당연한 얘기로 처리 순서와 관련된 사항이다.

가장 먼저 Intro 파일을 실행하고 파일에서 내용을 확인한 후 MainActivity 로 이동하거나 Upgrade 로 이동한다.

블로그 이미지

Link2Me

,
728x90

GitHub 에 소스를 보면

dependencies {
    compile project(':usbSerialForAndroid')
}

라고 되어 있는 경우가 있다.


이런 경우에는 어떻게 해야 프로젝트에 포함시켜 컴파일 할 수 있을까?


먼저, setting.gradle 파일을 열어서 프로젝트명을 본다.

include ':usbserialport'

라고 되어 있는 것이 보일 것이다.

여기에 추가를 한다.


include ':usbserialport'
include ':usbserialport:usbSerialForAndroid'


이제 실제 파일을 어떤 폴더에 넣는지 보자.



폴더를 여기에 넣었다.


build.gradle 에서는

 dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    compile project('usbSerialForAndroid')
}

로 적어주면 된다.


만약 libs 밑에 추가하고자 한다면 setting.gradle 에서는


include ':usbserialport'
include ':usbserialport:libs:usbSerialForAndroid'


라고 적어주고,


build.gradle 에서는

compile project('libs:usbSerialForAndroid')

라고 적어주면 된다.


이렇게 하고 나면 소소하게 발생하는 에러는 수정해주면 된다.

블로그 이미지

Link2Me

,
728x90

Android Studio 3.0.3 에서 업데이트를 시도하면 fonts.xml 파일이 수정되었다고 업그레이드가 계속 거부되어 포기하고 있다가, 다른 PC에서 새로 Android Studio 3.1.3 을 설치한 폴더를 별도 폴더를 만들어서 실행했더니 내부적으로 코드를 업데이트하더니 잘되던 프로젝트 코드가 전혀 인식도 안되고 동작이 안된다.


지금으로서는 괜히 업그레이드를 했나 싶을 정도로 맨붕 상태다.

한동안 안드로이드 코드는 들여다보지 않다가 시도하려니 그나마 알던 것도 기억 저편에서도 사라졌는지 하나도 생각나지 않는다.


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:23.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
}


2018년까지만 compile 로 dependencies 사용이 가능하고 그 이후에는 무조건 implementation 을 사용해야 한다는 내용이 나온다.


모듈 import 를 해도 기존 버전 파일을 인식하지 못하여 폴더 생성을 자동으로 하지 못한다.

폴더를 그냥 복사해서 넣으면 이미 있다고 나온다.

검색해보니 gradle-wrapper.properties 에서 4.4 로 되어 있는데 아래와 같이 변경하란다.

distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 으로 변경 했더니 에러 발생한다.

시간이 엄청 오래 걸린다. 다시 버전을 4.5 로 변경하고 Sync now 를 눌러서 재빌드 중이다.

4.5로의 변경은 성공이라고 나온다. 하지만 모듈 import 는 실패된다. 실제 폴더에 파일은 복사되어 있다.

Minimum supported Gradle version is 4.4. Current version is 4.3.

그래서 원복으로 4.4 로 변경하고 포기했다.


The specified Android SDK Build Tools version (26.0.2) is ignored, as it is below the minimum supported version (27.0.3) for Android Gradle Plugin 3.1.3.
Android SDK Build Tools 27.0.3 will be used.


신규로 Module를 생성하는 것은 잘된다. 그래서 모듈을 별도 생성하면서 처리하는 중이다.





블로그 이미지

Link2Me

,
728x90

새로운 기능을 테스트할 때마다 Android Studio 앱 gradle 설정시마다 세팅정보 맞추는데 힘들어서 적어둔다.


android {
    compileSdkVersion 23
    buildToolsVersion "25.0.0"

    defaultConfig {
        applicationId "com.tistory.link2me.carousel"
        minSdkVersion 19
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.squareup.okhttp3:okhttp:3.9.0' // 서버와의 통신 라이브러리
    compile 'com.squareup.picasso:picasso:2.5.2' // 이미지 라이브러리
    compile 'com.android.support:recyclerview-v7:23.2.1' // ListView 개선 버전
    compile "com.android.support:cardview-v7:23.2.1"


너무 최신버전으로 컴파일 하지 않으려고 하다보니 버전에 맞는걸 찾아서 적어줘야 하더라.

dependencies 에 추가되는 라이브러리 버전이 다르니까 밑줄이 그어지면서 수정하라고 나온다.


테스트하는 어플 기능이 이 라이브러리를 모두 필요로 하는 것은 아니지만 기본적으로 추가해두고 테스트를 하고 있다.


Android Studio 를 3.0 으로 업그레이드 했더니

buildToolsVersion "26.0.2" 으로 변경하라고 나온다.

buildToolsVersion "25.0.0" 은 에러가 발생하면서 계속 수정하라는 에러를 보여준다.


 dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:23.2.1'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.synnapps:carouselview:0.0.9'
    implementation 'com.squareup.picasso:picasso:2.5.2'  // 이미지 라이브러리
    implementation 'com.android.support:recyclerview-v7:23.2.1' // ListView 개선 버전
    implementation 'com.android.support:cardview-v7:23.2.1'
}


Android Studio 3.0 에서는 dependencies 에 compile 대신 implementation 으로 변경되었나 보다.




블로그 이미지

Link2Me

,