Migration from UPNS Below 5.0 to 5.1

Note

최신 샘플 및 라이브러리는 아래 링크를 통해, 다운로드 받을 수 있습니다.

1. 개요

Morpheus 플랫폼에서 제공하는 푸시 서비스 중, UPNS 5.0 이하 버전을, UPNS 5.1로 변환하기 위한 문서이다.

Warning

google paly 정책변경으로, targetSDK26 이상 빌드 / 배포 필요

  • 신규 앱 : 2018.08. 이후

  • 기존 앱 : 2018.11. 이후

targetSDK 26 이상은 BackgroundService API 사용 제약으로, JobScheduler or JobDispatcher 가 적용되어야 함에 따라 5.1 마이그레이션이 필요함

2. 변환 순서 (Morpheus IDE 환경)

  • Morpheus Project 를 Gradle 환경으로 변환

  • AndroidManifest.xml GCM 속성을 FCM 으로 변환

  • AndroidManifest.xml UPNSService 를 UPNSJobSerivce 로 변경

  • Manifest.xml use-permission 속성 추가

  • AndroidManifest.xml MPUSH_PERMISSION 속성 추가

  • FCM console 에서 google-service.json 파일 다운로드 및 적용

  • build.gradle 설정

2.1. Morpheus Project 를 Gradle 환경으로 변환

가. 방법 1 (Android Studio 이용)

나. 방법 2 (모피어스 IDE 기능 이용)

2.2. Manifest.xml 수정

가. use-permission 속성 추가

<settings>
   <push>
       <receiver>
           <!-- 브로드캐스트 리시버에서 퍼미션 사용 여부를 설정 (Y/N) android 8.0 이상 필수 -->
           <use-permission>Y</use-permission>
       </receiver>
   </push>
</settings>

2.3. AndroidManifest.xml 수정

가. GCM 속성 제거

 <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <!-- for Gingerbread GSF backward compat -->
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="[패키지명]" />
        </intent-filter>
    </receiver>

    <service android:name="m.client.push.library.service.GCMIntentService" android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>

    <service android:name="m.client.push.library.service.GCMInstanceIDListenerService" android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>

<permission android:name="[패키지명].permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="[패키지명].permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

나. FCM 속성 추가

<service android:name="m.client.push.library.service.FCMIntentService" android:exported="false">
     <intent-filter>
         <action android:name="com.google.firebase.MESSAGING_EVENT" />
     </intent-filter>
 </service>

 <!-- Internal (not exported) receiver used by the app to start its own exported services
      without risk of being spoofed. -->


 <!-- FirebaseInstanceIdService performs security checks at runtime,
      no need for explicit permissions despite exported="true" -->
 <service android:name="m.client.push.library.service.FCMInstanceIDListenerService" android:exported="true">
     <intent-filter >
         <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
     </intent-filter>
 </service>

다. UPNS 속성 [BackgroundService] 제거

<service android:name="m.client.push.library.service.UPNSService" android:exported="true" />

라. UPNS 속성 [Scheduler] 추가

<service android:name="m.client.push.library.service.UPNSJobService" android:exported="false">
     <intent-filter>
         <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
     </intent-filter>
</service>

<service android:name="m.client.push.library.service.UPNSConnectService"
             android:exported="false"/>

마. MPUSH_PERMISSION 속성 추가

<permission android:name="${applicationId}.MPUSH_PERMISSION" android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.MPUSH_PERMISSION" />

바. FOREGROUND_SERVICE 속성 추가

<!-- 안드로이드 9.0 이상 필수 : targetSdkVersion = 28 이상인 경우 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

2.4 FCM console 에서 google-service.json 파일 다운로드 및 적용

나. 적용 위치app/ 또는 module

모피어스 프로젝트의 경우, 프로젝트 root에 저장

2.5. Gradle Settings

  • dependencies 선언(적용 버전은 유동적임)

    implementation ('com.google.firebase:firebase-messaging:15.0.2')
    
  • apply plugin 선언(build.gradle 최하단에 위치 해야 함)

    apply plugin: 'com.google.gms.google-services'
    

2.6. build.gradle Sample [Morpheus IDE]

Warning

Gradle은 예시이므로, 프로젝트 상황에 맞게 재구성 필요

  • Sample [Project]

buildscript {
        repositories {
                jcenter()
                maven {url "https://maven.google.com"}
                maven {url "https://jcenter.bintray.com"}
        }

        dependencies {
                classpath 'com.android.tools.build:gradle:3.0.1'
                classpath 'com.google.gms:google-services:3.1.0'
                classpath 'com.github.ksoichiro:gradle-eclipse-aar-plugin:+'
        }
}

apply plugin: 'com.android.application'
apply plugin: 'com.github.ksoichiro.eclipse.aar'

repositories {
        jcenter()
        maven {url "https://maven.google.com"}
        maven {url "https://jcenter.bintray.com"}
}

android {
        compileSdkVersion 27
        buildToolsVersion "27.0.2"
        sourceSets {
                main {
                        manifest.srcFile 'AndroidManifest.xml'
                        java.srcDirs = ['src']
                        resources.srcDirs = ['src']
                        aidl.srcDirs = ['src']
                        renderscript.srcDirs = ['src']
                        res.srcDirs = ['res']
                        assets.srcDirs = ['assets']
                        jniLibs {
                                srcDir 'libs'
                        }
                }

                instrumentTest.setRoot('tests')
                debug.setRoot('build-types/debug')
                release.setRoot('build-types/release')
        }

        defaultConfig {
                multiDexEnabled true
        }

        dexOptions {
                preDexLibraries = false
        }

        lintOptions {
                checkReleaseBuilds false
                abortOnError false
        }

        buildTypes {
                release {
                        //minifyEnabled true
                        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
                }
        }
}

dependencies {
        //구버전 중 빌드시 불 필요한 라이브러리는 exclude 처리 한다. [support-v4, gcm]
    compile fileTree(dir: 'mcoreLibs', include: '*.jar', exclude: ['android-support-v4.jar', 'google-play-gcm.jar'])
    compile 'com.android.support:appcompat-v7:23.0.1'

        // fcm sdk (필수)
    implementation ('com.google.firebase:firebase-messaging:15.0.2')

        // JobScheduler sdk (필수)
    implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
}

apply plugin: 'com.google.gms.google-services'

2.7. build.gradle Sample [AndroidStudio]

Warning

Gradle 환경은 예시이므로, 프로젝트 상황에 맞게, 라이브러리 및 라이브러리 버전 재구성 필요

  • Sample [Project]

buildscript {

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.2'
        classpath 'com.google.gms:google-services:3.1.0'


        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {

    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
  • Sample [Module]

apply plugin: 'com.android.application'
repositories {
    maven { url 'https://maven.google.com' }
}


android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"

    defaultConfig {
        applicationId "kr.co.pushdemo"
        minSdkVersion 14
        targetSdkVersion 26
        multiDexEnabled true
    }

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

dependencies {
        //구버전 중 빌드시 불 필요한 라이브러리는 exclude 처리 한다. [support-v4, gcm]
    implementation files('libs/*.jar', exclude: ['android-support-v4.jar', 'google-play-gcm.jar'])

    implementation 'com.android.support:support-v4:26.1.0'
// fcm sdk (필수)
    implementation ('com.google.firebase:firebase-messaging:15.0.2')
        // JobScheduler sdk (필수)
    implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
}

apply plugin: 'com.google.gms.google-services'

2.8. Gradle Build시 주의 사항

Warning

아래와 같이 Error가 발생하는 경우, dependencies 속성이 Gradle 버전과 맞지 않기 때문이므로, implementation 을 compile 로 변경한다.

Error : A problem occurred evaluating project ‘:app’. > Could not find method implementation() for arguments

2.9. AndroidManifest.xml 예시

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.push.democlient"
    android:versionCode="1"
    android:versionName="1.0.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="27" />

        <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <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.RECEIVE_BOOT_COMPLETED"/>

    <!-- 안드로이드 8.0 이상 필수, 리시버 등록 시 권한 등록위해 선언 (필수), Manifest.xml 의 use-permission Y 선언 필요  -->
    <permission android:name="com.push.democlient.permission.MPUSH_PERMISSION" android:protectionLevel="signature" />
    <uses-permission android:name="com.push.democlient.permission.MPUSH_PERMISSION" />

    <!-- 안드로이드 9.0 이상 필수 : targetSdkVersion = 28 이상인 경우 -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"

        android:theme="@style/AppTheme">

        <activity
            android:name="com.push.democlient.MainActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Black.NoTitleBar"
            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="LoginActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar"></activity>
        <activity android:name="SecretMessageActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar"></activity>
        <activity android:name="PushMessageActivity" android:exported="true" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar"></activity>
        <activity android:name="PushDetailActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar"></activity>
        <activity android:name="PushListActivity" android:screenOrientation="portrait" android:theme="@android:style/Theme.Black.NoTitleBar"></activity>
        <activity android:name="ShowPushPopup" android:taskAffinity="com.push.democlient.pushpopup" android:excludeFromRecents="true" android:launchMode="singleTask" android:windowSoftInputMode="adjustUnspecified|adjustPan" android:screenOrientation="portrait" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"/>

        <service
            android:name="m.client.push.library.service.UPNSJobService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" />
            </intent-filter>
        </service>

       <service android:name="m.client.push.library.service.UPNSConnectService"
                    android:exported="false"/>

        <receiver android:name="m.client.push.library.receiver.ServiceHandleReceiver">
            <intent-filter>
                <action android:name="com.push.democlient.START_PUSHSERVICE" />
                <action android:name="com.push.democlient.STOP_PUSHSERVICE" />
                <action android:name="com.push.democlient.RESTART_PUSHSERVICE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.SCREEN_OFF" />
                <action android:name="android.intent.action.SCREEN_ON" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </receiver>



       <service android:name="m.client.push.library.service.GCMIntentService" android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>


        <!-- FirebaseInstanceIdService performs security checks at runtime,
             no need for explicit permissions despite exported="true" -->
        <service android:name="com.google.firebase.iid.FirebaseInstanceIdService" android:exported="true">
            <intent-filter android:priority="-500">
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>


        <receiver android:name="com.push.democlient.receiver.MessageArrivedReceiver">
            <intent-filter>
                <action android:name="com.push.democlient.UPNS_MESSAGE_ARRIVED" />
                <action android:name="com.push.democlient.GCM_MESSAGE_ARRIVED" />
            </intent-filter>
        </receiver>

        <receiver android:name="m.client.push.library.receiver.GcmActionReceiver">
            <intent-filter>
                <action android:name="com.push.democlient.ACTION_GCM" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <receiver android:name="m.client.push.library.receiver.UpnsActionReceiver">
            <intent-filter>
                <action android:name="com.push.democlient.ACTION_UPNS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

2.10. Manifest.xml 예시

<?xml version="1.0" encoding="UTF-8"?>
<settings>
        <push>
                <receiver>
                        <file-log>n</file-log>
                        <log>y</log>

                        <!-- 라이선스 발급시 별도로 부여 받기 바랍니다.-->
                        <security-indexes></security-indexes>

                        <!-- UPMC 서버 버전 -->
                        <version>5.0</version>

                        <!-- UPMC server url(필수 설정) -->

                        <server>http://xxx.xxx.148.97:8080</server>

                        <timeout>20000</timeout>

                        <!-- FCM설정 -->
                        <!-- FCM sender-id (push-type이 GCM/ FCM/ ALL일경우 필수설정) -->
                        <fcm-sender-id>xxxxxxx</fcm-sender-id>

                        <!-- 푸쉬타입(필수설정)
                 GCM:구글GCM / FCM(Public Push)
                 UPNS:유라클UPNS(Private Push) - 클라이언트 5.1 이상은 ALL 로 적용
                 ALL : FCM / UPNS 연동시
                        -->
                        <android-push-type>ALL</android-push-type>


                        <!-- 서비스 정책 ,
                         user : one user multidevice,
                         device : one user one device,
                         default : user -->
                        <policy>device</policy>

                        <!-- stb(셋탑)/mobile(모바일)/mobile_old(디바이스 아이디 이전 버전) -->
                        <device-type>mobile</device-type>

                        <!-- 브로드캐스트 리시버에서 퍼미션 사용 여부를 설정 (Y/N) -->
                        <use-permission>Y</use-permission>
                </receiver>

                <upns>
                        <!-- agent, inapp -->
                        <agent-service-type>inapp</agent-service-type>

                        <!-- UPNS RESTART ALARM INTERVAL (초단위) -->
                        <agent-restart-interval>120</agent-restart-interval>

                        <!-- auto/manual -->
                        <agent-receive-confirm>auto</agent-receive-confirm>
                </upns>
        </push>
</settings>