# Android

{% hint style="warning" %}
이 문서는 React Native 환경에서의 IMQA SDK를 적용하는 방법을 제공합니다.&#x20;

[IMQA MPM, Crash 설치 가이드](https://docs.imqa.io/imqa-guide/installation/android)를 통해 IMQA agent 코드 적용 후, 이 문서의 내용을 추가적으로 적용해주세요.
{% endhint %}

## 1. 공통

### MPM Module install&#x20;

React native 환경에서 IMQA SDK 적용을 위해 아래 명령어를 통해 패키지를 설치해주어야 합니다.&#x20;

{% code title="npm 명령어 사용시 " %}

```
// npm install imqa-react-native-agent --save 
```

{% endcode %}

{% code title="yarn 명령어 사용시" %}

```
yarn add imqa-react-native-agent
```

{% endcode %}

## 2. 그래들 플러그인 (Gradle Plugin) 설치&#x20;

‘app.gradle’ 파일에서 ‘buildscript’ 내 ‘dependencies’ 블럭에 ‘imqa-mpm-injector’ 와 상단에 ‘plugin’을 추가합니다. 일반적으로 ‘\<project\_dir>/app/build.gradle’ 에 있습니다.

{% hint style="warning" %}
파일을 업데이트 한 후 Gradle 파일을 동기화 해야 합니다.
{% endhint %}

{% code title="app.gradle(project root)" %}

```java
/// Add Build script dependencies 
buildscript { 
    repositories { 
        mavenCentral()
    } 
    
    dependencies {
    // dependencies 추가
        classpath 'io.imqa:imqa-mpm-injector:2.25.6' ... 
    } 
} 
```

{% endcode %}

* java

{% code title="app.gradle(app module) -> java" %}

```java
...
    dependencies {
    // dependencies 추가
       implementation 'io.imqa:imqa-core:2.27.3'
       implementation 'io.imqa:imqa-mpm-client:2.27.7'
       implementation 'io.imqa:imqa-crash-client:2.27.2'
    } 
} 

io.imqa.IMQAPlugin imqaPlugin = new io.imqa.IMQAPlugin()
imqaPlugin.init(project)
new io.imqa.injector.GJavacAction(project.name).setConfiguration(project)
android.applicationVariants.all { variant ->
    variant.javaCompile.doLast { task ->
        new io.imqa.injector.CompileAction(
                io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.javacClasses,
                project.name,
                io.imqa.injector.GJavacAction.convertBuildType(variant.getBuildType()),
                io.imqa.injector.GJavacAction.makeFlavor(variant.getBuildType().name,
                        variant)
        ).execute(task)
    }

```

{% endcode %}

* kotlin

{% code title="app.gradle(app module) -> kotlin" %}

```kotlin
...
    dependencies {
    // dependencies 추가
       implementation 'io.imqa:imqa-core:2.27.3'
       implementation 'io.imqa:imqa-mpm-client:2.27.7'
       implementation 'io.imqa:imqa-crash-client:2.27.2'
    } 
} 

io.imqa.IMQAPlugin imqaPlugin = new io.imqa.IMQAPlugin()
imqaPlugin.init(project)
new io.imqa.injector.GJavacAction(project.name).setConfiguration(project)
android.applicationVariants.all { variant ->
    variant.javaCompile.doLast { task ->
        new io.imqa.injector.CompileAction(
                io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.kotlin,
                project.name,
                io.imqa.injector.GJavacAction.convertBuildType(variant.getBuildType()),
                io.imqa.injector.GJavacAction.makeFlavor(variant.getBuildType().name,
                        variant)
        ).execute(task)
    }
}
```

{% endcode %}

* java + kotlin

{% code title="app.gradle(app module) -> java + kotlin" %}

```java
...

    dependencies {
    // dependencies 추가
       implementation 'io.imqa:imqa-core:2.27.3'
       implementation 'io.imqa:imqa-mpm-client:2.27.7'
       implementation 'io.imqa:imqa-crash-client:2.27.2'
    } 
} 

io.imqa.IMQAPlugin imqaPlugin = new io.imqa.IMQAPlugin()
imqaPlugin.init(project)
new io.imqa.injector.GJavacAction(project.name).setConfiguration(project)
android.applicationVariants.all { variant ->
    variant.javaCompile.doLast { task -> {
        new io.imqa.injector.CompileAction(
                io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.kotlin,
                project.name,
                io.imqa.injector.GJavacAction.convertBuildType(variant.getBuildType()),
                io.imqa.injector.GJavacAction.makeFlavor(variant.getBuildType().name,
                        variant)
        ).execute(task)

        new io.imqa.injector.CompileAction(
                io.imqa.injector.util.BuildOption.BUILD_LOCATION_TYPE.javacClasses,
                project.name,
                io.imqa.injector.GJavacAction.convertBuildType(variant.getBuildType()),
                io.imqa.injector.GJavacAction.makeFlavor(variant.getBuildType().name,
                        variant)
        ).execute(task)
    }
    }
}
```

{% endcode %}

{% code title="gradle.properties" %}

```
...

project.home=프로젝트의 경로 (ex:/user/workspace/project1)
#코틀린 프로젝트일경우에만 추가
project.kotlin.path=$PROJECT_HOME/app/build/tmp/kotlin-classes 
#자바 프로젝트일경우에만 추가
project.java.path=$PROJECT_HOME/app/build/intermediates/javac/debug/classes
#빌드된 manifest파일의 경로
project.manifest.path=$PROJECT_HOME/app/build/intermediates/merged_manifest/debug/AndroidManifest.xml
#gradle action
project.task.execute=:assemble

```

{% endcode %}

## 3. Android Manifest에 권한 추가&#x20;

AndroidManifest.xml 에 발생한 크래시 정보를 업로드 하기 위해 인터넷 권한을 주어야합니다.

{% code title="AndroidManifest.xml" %}

```xml
<uses-permission android:name="android.permission.INTERNET"/>
```

{% endcode %}

## 4. 소스코드에 IMQA초기화 코드 삽입

### IMQA 시작 코드 작성

{% hint style="warning" %}
Activity 가 아닌 Application 클래스에 삽입해야 합니다.

이때 ‘PROJECT\_KEY’ 부분에 복사한 ‘Project Key’ 값을 넣어줍니다.
{% endhint %}

{% code title="MyApplication.java" %}

```java
...
@Override
public void onCreate() {
    super.onCreate();
    io.imqa.core.IMQAOption imqaOption = new io.imqa.core.IMQAOption();
    imqaOption.setBuildType(false);
    imqaOption.setUploadPeriod(true);
    imqaOption.setKeepFileAtUploadFail(false);
    imqaOption.setDumpInterval(10000);
    imqaOption.setFileInterval(5);
    imqaOption.setHttpTracing(true);
    imqaOption.setRemoteControl(true);

    io.imqa.mpm.IMQAMpmAgent.getInstance()
        .setOption(imqaOption) // MPM 의 동작 방식을 정하는 옵션을 설정합니다.
        .setContext(this, BuildConfig.FLAVOR) 
        // Application Context 를 초기화 합니다. (Flavor 가 없는 경우 빈 문자열 삽입)
        .setProjectKey("PROJECT_KEY") 
        // IMQA MPM Client 의 Project Key 를 설정합니다.
        .init(); 
        // 등록한 옵션을 초기화 및 실행합니다.
    ...
}
...
```

{% endcode %}

{% code title="MyApplication.kt" %}

```kotlin
...
override fun onCreate() {
    super.onCreate()
    val imqaOption : IMQAOption = io.imqa.core.IMQAOption()
    imqaOption.setBuildType(false)
    imqaOption.setUploadPeriod(true)
    imqaOption.setKeepFileAtUploadFail(false)
    imqaOption.setDumpInterval(10000)
    imqaOption.setFileInterval(5)
    imqaOption.setHttpTracing(true)
    imqaOption.setRemoteConfig(true)

    io.imqa.mpm.IMQAMpmAgent.getInstance()
        .setOption(imqaOption) 
        // MPM 의 동작 방식을 정하는 옵션을 설정합니다.
        .setContext(this, BuildConfig.FLAVOR) 
        // Application Context 를 초기화 합니다. (Flavor 가 없는 경우 빈 문자열 삽입)
        .setProjectKey("PROJECT_KEY") 
         // IMQA MPM Client 의 Project Key 를 설정합니다.
        .init(); 
         // 등록한 옵션을 초기화 및 실행합니다.
    ...
}
...
```

{% endcode %}

### MPM Mode Option

IMQA MPM 실행 옵션을 파라미터나 Option을 이용해 변경할 수 있습니다. Android MPM Configuration Options 에서 실행 옵션을 확인하세요.

### 단축 모드

단축모드를 이용하여 IMQA MPM을 초기화 할 수 있습니다.

{% code title="MyApplication.java" %}

```java
...
override fun onCreate() {
    super.onCreate()

    io.imqa.mpm.IMQAMpmAgent.getInstance()
        .setContext(this, BuildConfig.FLAVOR) // Application Context 를 초기화 합니다. (Flavor 가 없는 경우 빈 문자열 삽입)
        .setProjectKey("PROJECT_KEY") // IMQA MPM Client 의 Project Key 를 설정합니다.
        .init() // 등록한 옵션을 초기화 및 실행합니다.
    ...
}
...
```

{% endcode %}

{% code title="MyApplication.kt" %}

```kotlin
...
override fun onCreate() {
    super.onCreate()

    io.imqa.mpm.IMQAMpmAgent.getInstance()
        .setContext(this, BuildConfig.FLAVOR) // Application Context 를 초기화 합니다. (Flavor 가 없는 경우 빈 문자열 삽입)
        .setProjectKey("PROJECT_KEY") // IMQA MPM Client 의 Project Key 를 설정합니다.
        .init() // 등록한 옵션을 초기화 및 실행합니다.
    ...
}
...
```

{% endcode %}

### ⚠️HTTPS (API level > 27)

Android API 28 부터 강화된 네트워크 보안 정책에 의해 HTTPS 요청이 필요해졌습니다. 이를 해결하기위해 다음 조치가 필요합니다.

1. **인증된 HTTPS 요청**\
   IMQA 서버로 인증된 HTTPS 를 요청하여 정상적으로 수집을 합니다.

{% code title="MyApplication.java or MyApplication.kt" %}

```kotlin
...
imqaOption.setServerUrl('https://collector.imqa.io');
...
```

{% endcode %}

2. &#x20;**강제 HTTP 요청**&#x20;

   이 flag를 설정하여 모든 cleartext 트래픽에 대해 허용처리를 할 수 있습니다.

{% code title="AndroidManifest.xml" %}

```xml
...
<application
    ...
    android:usesCleartextTraffic="true"
    />
...
```

{% endcode %}

### Zstandard 압축 알고리즘 사용

일반적인 gzip 이 아닌 보안성, 압축 효율이 높아진 Zstandard 압축 알고리즘을 사용할 수 있습니다. 이를 사용하기 위해 다음 설정이 필요합니다.

1. **MPM Mode Option 설정**\
   IMQA 시작 코드 삽입 시 설정에서 zstd 사용 여부를 설정할 수 있습니다.

{% code title="MyApplication.java or MyApplication.kt" %}

```kotlin
...
imqaOption.setCompressZstd(true);
...
```

{% endcode %}

2. **Zstd 라이브러리 추가**\
   ‘app.gradle’ 파일에서 ‘buildscript’ 내 ‘dependencies’ 블럭에 ‘zstd-jni’ aar 라이브러리를 추가합니다.

{% code title="app.gradle(app module)" %}

```java
...
    dependencies {
    // dependencies 추가
      ...
       implementation 'com.github.luben:zstd-jni:1.5.2-3@aar'
       ...
    }
} 
```

{% endcode %}

## 5. ⚠️현재 버전에서의 이슈 사항

1. **ASM**\
   ASM 을 사용하는 라이브러리와 충돌이 발생할 수 있습니다.<br>
2. **APK Repackaging**\
   APK Repackaging 중에 소스 라인정보가 사라집니다. 라인정보를 포함하고 싶으시다면 자동삽입 기능을 Compile 중에 실행해야 합니다.<br>
3. **Library 정보 수집**\
   Library 로 추가된 class 파일은 자동삽입 기능이 실행되지 않습니다. Library에서 수행되는 정보까지 수집하기 원하신다면 자동삽입 기능을 APK Repackaging 중에 실행해야 합니다.

## 6. 설치형 고객 필수 설정&#x20;

IMQA 설치형을 사용하시는 고객사에서는 반드시 수집서버를 설정해주시길 바랍니다.&#x20;

{% code title="MyApplication.java" %}

```java
...
@Override
public void onCreate() {
    super.onCreate();
    io.imqa.core.IMQAOption imqaOption = new io.imqa.core.IMQAOption();

    /*
     * 기본값 : 'https://collector.imqa.io'
     * MPM 서버 URL을 설정합니다.
     * String : 서버 정보
     */
    imqaOption.setServerUrl('https://(IPAddress)');

    io.imqa.mpm.IMQAMpmAgent.getInstance()
        .setOption(imqaOption) // MPM 의 동작 방식을 정하는 옵션을 설정합니다.
        .setContext(this, BuildConfig.FLAVOR) // Application Context 를 초기화 합니다. (Flavor 가 없는 경우 빈 문자열 삽입)
        .setProjectKey("PROJECT_KEY") // IMQA MPM Client 의 Project Key 를 설정합니다.
        .init() // 등록한 옵션을 초기화 및 실행합니다.
    ...
}
...
```

{% endcode %}
