일자 | 변경 내용 | 작성자 |
---|---|---|
2017.08.30 | Studio용 User Guide 작성 | 임희강 |
2017.11.10 | GCM -> FCM 으로 변경 | 임희강 |
2018.06.11 | 8.0 대응으로인해 apms.properties 수정 | 임희강 |
2018.07.18 | 8.0 대응, noti_o_badge,JobService 추가 | 손보광 |
2018.09.03 | 9.0 대응, MQTT 안정화 적용 | 손보광 |
파일명 | 설명 |
apms_sdk_base.jar | APMS 라이브러리 |
org.eclipse.paho.client.mqttv3-1.2.0.jar | Private Server 접속 라이브러리 |
volley_20160608.jar | APMS API 호출 시 사용하는 통신 라이브러리 |
Android Studio 의 해당 프로젝트에서 New
-> New Module
을 선택합니다.
선택후 다음과 같은 창이 뜨면 Import.JAR/.AAR Packge
를 선택한뒤 Next
를 클릭합니다.
전달해드린 라이브러리(.jar) 파일들을 선택하고 Finish를 선택하여 라이브러리를 추가하여 줍니다.
완료 후 다음과 같이 생성한 파일 이름으로 Module이 생성이 되게 됩니다.
File
-> Project Structure
를 선택합니다.
해당 Project
선택 후 Dependencies
탭을 선택합니다.
좌측 하단에 있는 +
버튼 후 Module dependency
를 선택합니다.
등록 했던 Module를 선택합니다. OK 버튼을 눌러 완료 합니다.
File
-> Project Structure
를 선택합니다.Dependencies
-> +
-> Library dependency
를 선택하여 다음 Library를 선택해 줍니다.
com.google.firebase:firebase-messaging
해당 프로젝트에 있는 build.gradle
파일을 오픈해서 dependencies 부분에classpath 'com.google.gms:google-services:3.0.0'
를 추가하여 중입니다.
buildscript {
...
dependencies {
....
classpath 'com.google.gms:google-services:3.0.0'
}
}
app/build.gradle
파일을 오픈해서 제일 하단에 apply plugin: 'com.google.gms.google-services
를 추가합니다.
apply plugin: 'com.google.gms.google-services'
그 후 오른쪽 상단에 뜨는 Sync Now
를 클릭하여서 Build를 완료합니다.
FCM을 받기위해 Firebase Console
등록시 다운로드 받았던 google-services.json
파일을 app
폴더 아래로 복사를 합니다.
<!-- push -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.VIBRATE" />
<!-- push -->
<!-- network -->
<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" />
<!-- network -->
<manifest>
태그내에 추가합니다.$(project_package)
는 manifest태그의 package를 의미합니다.$(project_package)
적용 예제 (Package Name이 "com.humuson.app"일 경우)<!-- push -->
<permission android:name="com.humuson.app.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.humuson.app.permission.C2D_MESSAGE" />
...
<service
android:name="com.apms.sdk.push.GetFCMInstanceID"
android:exported="false" >
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<service
android:name="com.apms.sdk.push.FCMPushService"
android:exported="false" >
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<application>
태그내에 추가합니다.<receiver
android:name="com.apms.sdk.push.PushReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="org.mosquitto.android.mqtt.MSGRECVD"/>
<category android:name="$(project_package)"/>
</intent-filter>
</receiver>
<application>
태그내에 추가합니다.$(project_package)
는 manifest태그의 package를 의미합니다.$(project_package)
적용 예제 (Package Name이 "com.humuson.app"일 경우)<receiver
android:name="com.apms.sdk.push.PushReceiver"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="org.mosquitto.android.mqtt.MSGRECVD"/>
<category android:name="com.humuson.app"/>
</intent-filter>
</receiver>
<!-- apms push popup activity -->
<activity
android:name="${push_popup_activity}"
android:theme="@style/push_popup_theme"
android:excludeFromRecents="true"
android:exported="false"
android:screenOrientation="portrait"
android:configChanges="orientation" />
<application>
태그내에 추가합니다.${push_popup_activity}
는 Push수신 시 출력될 Popup Activity의 className을 의미합니다.${push_popup_activity}
에 셋팅하시고, apms.properties의 push_popup_activity
의 값과 일치시켜 주시면 됩니다. <!-- apms push popup activity -->
<activity
android:name="com.custom.push.CusomPushPopupActivity"
android:theme="@style/push_popup_theme"
android:excludeFromRecents="true"
android:exported="false"
android:screenOrientation="portrait"
android:configChanges="orientation" />
push_popup_activity=com.custom.push.CusomPushPopupActivity
<!-- apms push clickNotiReceiver -->
<receiver android:name="${noti_receiver_class}" >
<intent-filter>
<action android:name="${noti_receiver}" />
</intent-filter>
</receiver>
<application>
태그내에 추가합니다.${noti_receiver_class}
는 Push수신 시 출력되는 상단의 Notification을 터치 했을 때, 수행될 Receiver의 className을 의미합니다.${noti_receiver}
는 Push수신 시 출력되는 상단의 Notification을 터치 했을 때, broadcasting할 intent action을 의미합니다.noti_receiver
항목에 noti receiver(intent action)를 일치시켜 주셔야 합니다.noti_receiver_class
항목에 noti receiver_class(class name)를 일치시켜 주셔야 합니다.<!-- apms push clickNotiReceiver -->
<receiver android:name="com.custom.push.CustomNotiReceiverClass" >
<intent-filter>
<action android:name="com.custom.push.notifiaction" />
</intent-filter>
</receiver>
noti_receiver=com.custom.push.notifiaction
noti_receiver_class=com.custom.push.CustomNotiReceiverClass
<!-- APMS Private RestartReceiver -->
<receiver android:name="com.apms.sdk.push.mqtt.RestartReceiver">
<intent-filter>
<action android:name="MQTT.START"/>
<action android:name="MQTT.FORCE_START"/>
</intent-filter>
</receiver>
<!-- Private PUSH Service -->
<service
android:name="com.apms.sdk.push.mqtt.MQTTService"
android:enabled="true"
android:exported="true"
android:label="PushService"
android:process="${process_name}" />
<application>
태그내에 추가합니다.${process_name}
는 Android Process Name을 의미합니다.${process_name}
적용 예제 (Process Name이 "com.apms.sdk.HumusonpushService"일 경우) <!-- Private PUSH Service -->
<service
android:name="com.apms.sdk.push.mqtt.MQTTService"
android:enabled="true"
android:exported="true"
android:label="PushService"
android:process="com.apms.sdk.HumusonpushService" />
<!-- APMS Data Sender Service -->
<service
android:name="com.apms.sdk.service.DataSenderService"
android:enabled="true"
android:exported="true"
android:label="SenderService"
android:process="${process_name}" />
<!-- APMS Data Sender receiver -->
<receiver android:name="com.apms.sdk.service.SenderSeviceReceiver" >
<intent-filter>
<action android:name="SENDER.START" />
<action android:name="SENDER.STOP" />
</intent-filter>
</receiver>
${process_name}
는 Android Process Name을 의미합니다.
${process_name}
적용 예제 (Process Name이 "com.apms.sdk.DataSenderService"일 경우)
<!-- APMS Data Sender Service -->
<service
android:name="com.apms.sdk.service.DataSenderService"
android:enabled="true"
android:exported="true"
android:label="SenderService"
android:process="com.apms.sdk.DataSenderService" />
<meta-data android:name="APMS_NOTI_CONTENT" android:value="${noti_content}" />
${noti_content}
적용 예제 (value가 "두손가락을 이용해 아래로 당겨주세요."일 경우)
<meta-data android:name="APMS_NOTI_CONTENT" android:value="두손가락을 이용해 아래로 당겨주세요." />
<meta-data android:name="APMS_NOTI_CONTENT" android:value="@string/finger_event" />
<meta-data android:name="APMS_SET_ICON" android:resource="@drawable/${icon_file_name}" />
<meta-data android:name="APMS_SET_LARGE_ICON" android:resource="@drawable/${icon_file_name}" />
${icon_file_name}
는 Notification Icon에 등록될 Icon File Name을 넣으시면 됩니다.<meta-data android:name="APMS_NOTI_BACK" android:value="\ #000000" />
\
(역슬러쉬)는 무조건적으로 해주셔야 합니다.<meta-data android:name="APMS_SET_NOTI_SOUND" android:resource="@raw/${ring_file_name}"/>
${ring_file_name}
Resource/Raw/ 저장한 벨소리 파일 네임을 넣으시면 됩니다.<!-- push popup theme -->
<style name="push_popup_theme" parent="android:Theme.Light">
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
</style>
####################### APMS #######################
# APMS App Key & API Server Url Setting
# GCM발송을 위한 앱의 projectId로 GCM의 pushToken을 가져오는데 사용됩니다.
gcm_project_id=${Google_Project_Number}
# APMS Admin Web에서 앱 생성 시 발급되는 key입니다.
app_key=${App_key}
# APMS Msg-Api Url을 의미합니다.
api_server_url=${Msg_Api_Url}
# Private Server Setting
# mqtt의 사용여부를 의미합니다. ("Y":사용, "N":사용하지 않음)
mqtt_flag=${mqtt_flag}
# private server와 연동 시 필요한 server url을 의미합니다.
# 반드시 다음과 같이 protocol, url, port를 전부 입력해주셔야 합니다. (사용하지 않을시에는 공백처리)
mqtt_server_url_ssl=${mqtt_ssl_url}
mqtt_server_url_tcp=${mqtt_tcp_url}
# Android 8.0에만 적용되는 사항으로 MQTT 포그라운드 서비스 이용시간을 의미합니다. 단위는 ms로 최소 60000(1분)값을 권장합니다
mqtt_wakeup_time=60000
# private server와의 keep alive time을 의미합니다. 단위는 초(second)입니다.
# (KeepAlive Total Time : Keep alive time + Ramdom Time(2~4min))
mqtt_server_keepalive=${mqtt_keepalive}
# DEBUG MODE
# Logcat 관련 설정 입니다.
debug_tag=APMS
debug_flag=Y
# Service에 대한 로그를 파일로 저장 유무를 설정합니다.
debug_log_falg=Y
# APMS SETTING
# Push 수신시 화면 On/Off를 의미 합니다.
screen_wakeup_flag=Y
# Notification Summary 기능 사용 여부 (Android 7.0이상부터 사용 가능합니다.)
noti_group_flag=Y
# Push 수신시 화면에 보여지는 시간을 의미 합니다. (단위 : ms)
push_popup_showing_time=9999999
# Push 노출을 앱 사용중에만 노출 할 것인지(디폴트값) 아니면
# 다른앱을 사용중에만 빼고 노출 할 것인지 설정값입니다. (default = N)
push_popup_showing_flag=N
# Push수신시 동작할 class name을 의미합니다.
(SDK에서 푸시 수신시 사용하는 PushReceiver와 다르며 사용하지 않으시려면 빈칸으로 두시면 됩니다. 직접 구현하셔야 합니다)
push_receiver_class=${push_receiver_class}
# Push수신 시 출력되는 상단의 Notification을 터치 했을 때, 동작할 intent action을 의미합니다.
noti_receiver=${noti_receiver}
# Push수신 시 출력되는 상단의 Notification을 터치 했을 때, 동작할 class name을 의미합니다.
noti_receiver_class=${noti_receiver_class}
# Push수신 시 출력될 Popup Activity의 className을 의미합니다.
# (Default Class : "com.apms.sdk.push.PushPopupActivity")
push_popup_activity=${push_popup_activity}
# Text Notification 생성시 BigText Mode 사용 여부 (사용 : Y , 미사용 : N)
big_text_mode=Y
####################### TAS #######################
# TAS API Url및 Image 파일 이름을 설정합니다.
# TAS에서 발급받은 채널키
tas_channel_key=${App_key}
# 트래킹 서버 URL
tas_server_url=https://img-amc.tason.com
tas_image_name=/amc.gif
# Android 8.0 이상에서 뱃지 카운트 자동 생성 사용 여부 (사용 : Y , 미사용 : N)
noti_o_badge=N
FCM발송을 위한 Project ID 가져오는 방법
Project Number
& API Key
가져오는 방법은 별도의 가이드 문서 참조.구글 광고 정책에 의해서 앱이 실행중에만 팝업이 노출되게 되어있습니다.
하지만, push_popup_showing_flag
를 Y
로 두시면 예전과 동일하게 사용가능 합니다.
noti_group_flag
은 Android 7.0 전용 기능입니다. 같은 앱에서 Notification을 여러개 수신하게 되면 하나의 그룹으로 지정해서 한번에 여러개 메세지를 보실 수 있습니다. (아래 이미지 참고)
pushNotiReceiver 추가
항목을 참조 하시기 바랍니다.Push Data
항목을 참조 하시기 바랍니다. package com.custom.push;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class CustomNotiReceiverClass extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// notification 터치 시에 “push notiMsg:${notiMsg}” 라는 텍스트를 Toast로 출력합니다.
Toast.makeText(contetx, "push notiMsg:" + intent.getStringExtra(APMS.KEY_NOTI_MSG),
Toast.LENGTH_SHORT).show();
}
}
intent.getStringExtra(APMS.KEY_MSG_ID) // "i" - 메세지 ID
intent.getStringExtra(APMS.KEY_NOTI_TITLE) // "notiTitle" - notification에 출력될 타이틀
intent.getStringExtra(APMS.KEY_NOTI_MSG) // "notiMsg" - notification에 출력될 메시지 내용
intent.getStringExtra(APMS.KEY_NOTI_IMG) // "notiImg" - notification에 출력될 이미지 URL
intent.getStringExtra(APMS.KEY_MSG) // "message" - (리치) 푸시 내용
intent.getStringExtra(APMS.KEY_SOUND) // "sound" - 푸시 수신 시 출력될 사운드
intent.getStringExtra(APMS.KEY_MSG_TYPE) // "t" - 메시지 타입 : H – html, T – Text, L – Link
intent.getStringExtra(APMS.KEY_POPUP_FLAG) // Popup 창을 제어하는 Flag
intent.getStringExtra(APMS.KEY_DATA) // "d" - 추가 데이터
PushMsg pushMsg = new PushMsg(intent.getExtras());
pushMsg.msgId // 메세지 ID
pushMsg.notiTitle // notification에 출력될 타이틀
pushMsg.notiMsg // notification에 출력될 메시지 내용
pushMsg.notiImg // notification에 출력될 이미지 URL
pushMsg.message // (리치) 푸시 내용
pushMsg.sound // 푸시 수신 시 출력될 사운드
pushMsg.msgType // 메시지 타입 : H – html, T – Text, L – Link
pushMsg.popupFlag // Popup 창을 뛰울지 말지 결정 Flag (Y & N)
pushMsg.data // 추가 데이터
// Device 가 6.0 이상일 경우
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
// 확인할 Permission 들을 추가할 ArrayList
ArrayList<String> strArrPermission = new ArrayList<String>();
// READ_PHONE_STATE 퍼미션이 존재 하지 않을 경우 퍼미션 추가 팝업을 띄위기 위해 ArrayList 에 추가
int permissionCheck = ContextCompat.checkSelfPermission([context],
Manifest.permission.READ_PHONE_STATE);
// 만약 해당 퍼미션이 없을 경우 ArrayList에 확인할 퍼미션을 추가합니다.
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
CLog.i("READ_PHONE_STATE PERMISSION_DENIED");
strArrPermission.add(Manifest.permission.READ_PHONE_STATE);
strArrPermission.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
// ACCESS_FINE_LOCATION 퍼미션이 존재 하지 않을 경우 퍼미션 추가 팝업을 띄위기 위해 ArrayList 에 추가
permissionCheck = ContextCompat.checkSelfPermission([context],
Manifest.permission.ACCESS_FINE_LOCATION);
// 만약 해당 퍼미션이 없을 경우 ArrayList에 확인할 퍼미션을 추가합니다.
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
CLog.i("ACCESS_FINE_LOCATION PERMISSION_DENIED");
strArrPermission.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
//ACCESS_COARSE_LOCATION 퍼미션이 존재 하지 않을 경우 퍼미션 추가 팝업을 띄위기 위해 ArrayList 에 추가
permissionCheck = ContextCompat.checkSelfPermission([context],
Manifest.permission.ACCESS_COARSE_LOCATION);
// 만약 해당 퍼미션이 없을 경우 ArrayList에 확인할 퍼미션을 추가합니다.
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
CLog.i("ACCESS_COARSE_LOCATION PERMISSION_DENIED");
strArrPermission.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
// ACCESS_NETWORK_STATE 퍼미션이 존재 하지 않을 경우 퍼미션 추가 팝업을 띄위기 위해 ArrayList 에 추가
permissionCheck = ContextCompat.checkSelfPermission([context],
Manifest.permission.ACCESS_NETWORK_STATE);
// 만약 해당 퍼미션이 없을 경우 ArrayList에 확인할 퍼미션을 추가합니다.
if (permissionCheck == PackageManager.PERMISSION_DENIED) {
CLog.i("ACCESS_NETWORK_STATE PERMISSION_DENIED");
strArrPermission.add(Manifest.permission.ACCESS_NETWORK_STATE);
}
// Permission 팝업을 띄위기 위한 String array 를 만들어 퍼미션 요청을 수행합니다.
if (strArrPermission.size() > 0) {
String[] strPermission = new String[strArrPermission.size()];
for (int i=0; i<strArrPermission.size(); i++) {
strPermission[i] = strArrPermission.get(i);
}
ActivityCompat.requestPermissions((Activity) this, strPermission, 0);
}
}
이 방법은 SDK와 별도로 제공되는 옵션입니다. 해당 앱에 직접 설정 하셔야 합니다.
삼성 계열의 장치에서만 동작하도록 설정 되어 있습니다.
동작은 방법은 충전을 위해서 케이블을 꼽을 때와 뽑을 때 동작을 하고 장치를 재부팅 시켰을 경우 동작을 하도록 하여 절전 기능으로 안 빠지게 되어 있습니다.
유의 사항은 앱을 사용 중에 충전 케이블을 꼽거나 뽑을 때 투명한 Activity가 화면에 뜨게 되어 눈에는 보이지 않지만 사용자가 계속 터치 중이거나 하면 잠깐 터치가 안될 수 도 있습니다
Androidmanifest.xml 설정
<activity
android:name="${Activity_Class}"
android:excludeFromRecents="true"
android:taskAffinity=":avoidSmartManager"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<receiver
android:name="${Receiver_Class}"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
public class AvoidSmartManagerActivity extends Activity {
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CLog.e("AvoidSmartManagerActivity!!!!");
finish();
}
}
Receiver Class (해당 클래스 명은 바꾸셔도 됩니다)
public class AvoidSmartManagerReceiver extends BroadcastReceiver {
private static final String SMART_MANAGER_PACKAGE_NAME = "com.samsung.android.sm";
@Override
public void onReceive (final Context context, Intent intent) {
CLog.d("onReceive() " + intent);
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) || Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())
|| Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
boolean isSmartManagerExist = false;
try {
context.getPackageManager().getPackageInfo(SMART_MANAGER_PACKAGE_NAME, PackageManager.GET_META_DATA);
isSmartManagerExist = true;
} catch (PackageManager.NameNotFoundException e) {
}
if (isSmartManagerExist) {
new Handler().postDelayed(new Runnable() {
@Override
public void run () {
Intent serviceIntent = new Intent(context, AvoidSmartManagerActivity.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(serviceIntent);
}
}, new Random().nextInt(3000));
}
}
}
}