메모형식으로 작성한 글입니다..


안드로이드 스튜디오에서 NDK로 C++11과 STL을 사용한 소스를 빌드하는 법.

C++가 아닌 C를 사용할 때는 makefile과 소스코드에서 약간의 차이가 있다. (본문 내에서 설명)



테스트 환경

Android Studio : 2.2.2

Gradle : 2.2.2

buildToolsVersion : 24.0.0




테스트 소스 코드

https://github.com/tibyte/practice-unclassified/tree/master/Android/NDKTest3




NDK 설치

File - Settings - Appearance & Behavior - System Settings - Android SDK

에서 SDK Tools로 들어가면 NDK를 설치할 수 있다.






javah 추가

File - Settings - Tools - External Tools에서 추가를 눌러 javah를 추가한다.

하단의 Tool settings에 들어갈 내용은 아래와 같다.

Program : jdk에 포함되어 있는 javah의 경로

Parameters : -v -jni -d $ModuleFileDir$/src/main/jni $FileClass$

Working directory : $SourcepathEntry$





java코드에서 네이티브 함수 사용

System.loadLibrary()로 사용할 라이브러리를 로드한다.  라이브러리 이름은 임의로 정해도 되는데, 이 글에서는 main.cpp를 만들 것이므로 여기에서는 main으로 정한다.

그리고 사용할 네이티브 함수명을 native키워드를 통해 선언한다.

package kr.tibyte.ndktest3;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

static {
System.loadLibrary("main");
}
public native String getNativeText();


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

TextView tv = (TextView)findViewById(R.id.text_view);

tv.setText(getNativeText());
}

} 





JNI용 헤더파일 생성


프로젝트 탭에서 보기 설정을 Project로 한다.




네이티브 함수를 사용한 Java파일을 우클릭하여 External Tools - javah를 클릭한다.

그러면 src/main/jni 경로에 프로젝트_경로.h파일이 생성된다. 






C++ 소스코드 작성

JNI디렉토리 내에 cpp파일을 만들고 소스코드를 작성하는데,

함수 이름에 패키지 경로가 들어있어야 한다. 이 부분이 실제 패키지 경로와 다르면 빌드가 되지 않는다. 아래 예제에서는 테스트 목적으로 STL과 C++11 기능을 사용했다. 

#include <jni.h>

#include <vector>

#include <string>

#include "kr_tibyte_ndktest3_MainActivity.h"


using namespace std;


extern "C" {


JNIEXPORT jstring JNICALL Java_kr_tibyte_ndktest3_MainActivity_getNativeText(JNIEnv *env, jobject obj)

{

    string str = "";

    vector<char> vec;

    vec.push_back('a');

    vec.push_back('b');

    vec.push_back('c');


    for(auto& x : vec) {

        x ^= 32;

        str += x;

    }


    return env->NewStringUTF(str.c_str());


}



이 부분에서 C와 C++의 차이는 다음과 같다.

- 소스코드 확장자 (.c, .cpp)
- C++문법 사용여부
- C++에서는 함수 형식이 JNIEXPORT jstring JNICALL이지만, C에서는 jstring
- JNI함수를 호출할 때 C++에서는 env->NewStringUTF("string") 형식을 사용하지만,
 C에서는 (*env)->NewStringUTF(env, "string"); 형식으로 리턴.

- C++에서 extern으로 네임 맹글링을 어떤 규칙으로 할 것인지 지정(참고링크)





Makefile 설정


jni디렉토리 안에 Android.mk와 Application.mk 파일을 생성하고 각각 아래와 같은 내용을 적는다.


Android.mk

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)


LOCAL_DEFAULT_CPP_EXTENSION := cpp

LOCAL_MODULE    := main

LOCAL_SRC_FILES := main.cpp

LOCAL_LDLIBS    := -llog -latomic

LOCAL_C_INCLUDES := $(LOCAL_PATH)/include-all


include $(BUILD_STATIC_LIBRARY)

C로 빌드할 때에는 LOCAL_DEFAULT_CPP_EXTENSION := cpp가 필요하지 않다.

LOCAL_MODULE과 LOCAL_SRC_FILES는 작성한 C/C++네이티브 소스파일과 관련된 내용을 적는다.


Application.mk

NDK_TOOLCHAIN_VERSION := 4.9

APP_STL := gnustl_static

APP_MODULED := main

APP_ABI := armeabi-v7a

APP_CPPFLAGS += -std=c++11

LOCAL_C_INCLUDES += ${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.9/include

NDK_TOOLCHAIN_VERSION : NDK설치경로/sources/cxx-stl/gnu-libstdc++ 에 있는 툴체인 버전을 적는다.

APP_STL : 정적 라이브러리를 사용하고 싶을 경우 gnustl_static를, 공유라이브러리를 쓸 대는 gnustl_shared를 적을 수 있다.

APP_ABI : 빌드할 대상 아키텍쳐를 적는다. all로 적으면 모든 대상으로 빌드할 수 있다.

APP_CPPFLAGS : C++11로 빌드하려면 -std=c++11 플래그를 넣는다.

LOCAL_C_INCLUDES : 자신이 가진 버전에 맞는 경로를 적는다. (NDK설치경로 확인)





build.gradle ndk 정보 추가

src디렉토리 내에 있는 defaultConfig안에 다음과 같은 내용을 추가한다.

 ndk {

stl "gnustl_static"

moduleName "main"

}

stl에서 gnustl_static은 Application.mk에서 설정했던 것과 같은 것이고,

moduleName은 Android.mk, Application.mk, java파일에서 썼던 것과 같다.

만약 STL을 사용하지 않을 것이면 stl은 작성하지 않아도 된다..




실행화면

STL vector와 C++11의 auto를 사용한 코드가 정상적으로 빌드된다. 











이 글을 작성했을 때보다 더 나중에 나온

안드로이드 스튜디오 2.2.2로 빌드하는 방법을 새로 작성하였습니다.

http://tibyte.kr/272








개발환경

Windows 10 64bit

Android Studio 1.5.1

jdk 1.8.0_71


target sdk version : 23

min sdk version : 15


기본 설정


- JDK 설치

- JDK 환경변수 (PATH)설정

- 안드로이드 스튜디오 설치

- NDK 다운로드


안드로이드 스튜디오에서 새 프로젝트를 만든다. 

이 포스트에서는 프로젝트 이름을 ndktest로 정한다.


프로젝트 창에서는 Project Files를 선택해야 디렉터리 경로를 보기 쉽다.





File - Project Structure - Android NDK location 에서 다운받은 NDK 경로를 지정한다.

안드로이드 스튜디오를 통해 설치했다면 자동지정된다.






java 어플리케이션 만들기


안드로이드에서 빈 액티비티로 프로젝트를 만들면 TextView하나가 나와있는데,

C/C++ 네이티브 코드에서 보낸 메시지를 여기에 띄워 본다.


프로젝트 디렉터리를 기준으로

app/src/main/res/layout/content_main.xml 

파일에 있는 TextView에게 id를 붙여준다.


    android:id="@+id/textView" 



MainActivity.java 파일에 네이티브 라이브러리를 로드하는 구분과 메서드 선언을 적는다.


  static {

       System.loadLibrary("ndktest");

   }

   public native String getStringFromNative();



onCreate 메서드 내에서는 위에서 선언한 함수를 호출하여 텍스트뷰에 쓴다.


 TextView view = (TextView)findViewById(R.id.textView);

 view.setText(getStringFromNative());



Build - Make Project로 빌드한다.




javah로 JNI용 C++ 헤더파일 제작


이 작업을 하기 전에 먼저 환경변수에 ANDROID_HOME이라는 값을 안드로이드 SDK 경로로 지정해 두면 편하다.



Windows 환경에서 안드로이드 스튜디오를 통해 안드로이드 SDK를 설치했을 때 기본 경로는 C:\Users\유저이름\AppData\Local\Android\sdk 이다.


프로젝트 디렉터리를 기준으로

app/src/main

으로 이동하여 커맨드창을 열고 다음과 같이 javah를 실행한다. (Windows 기준)

도메인 경로와 프로젝트 이름(여기서는 ndktest)는 프로젝트에 맞게 설정.


$ javah -d jni -classpath %ANDROID_HOME%/platforms/android-23/android.jar;%ANDROID_HOME%/extras/android/support/v7/appcompat/libs/android-support-v7-appcompat.jar;%ANDROID_HOME%/extras/android/support/v4/android-support-v4.jar;../../build/intermediates/classes/debug 도메인.경로.ndktest.MainActivity


만약 ANDROID_HOME 경로의 extras/android 디렉터리에 support가 없다면

Tools - Android - SDK Manager - Appearance - System Settings - Android SDK - SDK Tools 로 들어가

Android Support Library 를 설치한다.


성공적으로 실행되었다면

app/src/main/jni 에 헤더파일(.h)이 생성된다.




C++ 네이티브 코드 작성


간단한 C++ 코드를 작성한다.

여기서 주의할 점은 위에서 생성한 헤더파일을 로드해야하고, 함수 이름도

Java_도메인_경로_프로젝트이름_Java클래스명_Java메서드명 형식으로 되어야 한다는 것이다.


JNIEXPORT jstring JNICALL Java_kr_tibyte_ndktest_MainActivity_getStringFromNative(JNIEnv *env, jobject obj)


아래 코드에 있는 도메인 (kr_tibyte)는 프로젝트에 맞게 고친다.


#include "kr_tibyte_ndktest_MainActivity.h"

#include <string>

#include <sstream>


using namespace std;


JNIEXPORT jstring JNICALL Java_kr_tibyte_ndktest_MainActivity_getStringFromNative(JNIEnv *env, jobject obj) {


    stringstream ss;

    for(int i=1; i<=9; i++) {

        for (int j=1; j<=9; j++) {

            int n = i*j;

            ss << " ";

            if(n < 10) ss << "0";

            ss << n;

        }

        ss << endl;

    }


    string str = ss.str();

    return env->NewStringUTF(str.c_str());

}






makefile(*.mk) 설정


app/src/main/jni 안에 Android.mk를 만든다.

LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS)


LOCAL_MODULE    := ndktest

LOCAL_SRC_FILES := main.cpp

LOCAL_LDLIBS := -llog


include $(BUILD_SHARED_LIBRARY) 


LOCAL_MODULE은 생성될 네이티브 모듈의 이름,

LOCAL_SRC_FILES는 모듈을 만드는 데 사용될 소스파일들의 목록이다.



app/src/main/jni 안에 Application.mk를 만든다.


APP_ABI := armeabi

APP_STL := gnustl_static


여기서는 컴파일을 위한 옵션 플래그들을 지정할 수 있다.

APP_STL을 지정하여 C++에서 STL 요소들을 사용할 수 있다.


APP_ABI는 ABI(Application Binary Interface)를 지정할 수 있는데 armeabi, armeabi-v7a, mips, x86등이 있으니 필요에 따라 설정한다.






gradle 설정

app/build.gradle을 수정한다.


apply plugin: 'com.android.application'


android {

    compileSdkVersion 23

    buildToolsVersion "23.0.2"


    defaultConfig {

        applicationId "kr.tibyte.ndktest"

        minSdkVersion 15

        targetSdkVersion 23

        versionCode 1

        versionName "1.0"

    }

    buildTypes {

        release {

            minifyEnabled false

            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }

        debug {

            jniDebuggable true

        }

    }


    sourceSets.main {

        //네이티브 라이브러리 경로

        jniLibs.srcDir 'src/main/libs'

       //JNI소스 경로

        jni.srcDirs = []

    }


   //안드로이드 스튜디오에서 Java 소스를 빌드할 때 buildNative task를 실행시킴

    tasks.withType(JavaCompile) {

        compileTask -> compileTask.dependsOn buildNative

    }


   //네이티브 소스 빌드

    task buildNative(type: Exec, description: 'Compile JNI source via NDK') {

        def ndkDir = android.ndkDirectory

        commandLine "$ndkDir/ndk-build.cmd", 'NDK_DEBUG=1', '-C', file('src/main').absolutePath

    }


    //네이티브 라이브러리 삭제

    task cleanNative(type: Exec, description: 'Clean JNI object files') {

        def ndkDir = android.ndkDirectory

        commandLine "$ndkDir/ndk-build.cmd", '-C', file('src/main').absolutePath, 'clean'

    }

    

    clean.dependsOn 'cleanNative'


}

dependencies {

    compile 'com.android.support:appcompat-v7:23.1.1'

    compile 'com.android.support:design:23.1.1'

}





결과


이제 애플리케이션을 빌드하고 기기에서 실행시키면

C++ 코드에서 처리한 결과가 MainActivity의 TextView로 표시된다.





코드 모음


https://github.com/tibyte/practice/tree/master/android/ndktest





참조


https://stackoverflow.com/questions/21096819/jni-and-gradle-in-android-studio

http://stackoverflow.com/questions/21999829/how-do-i-read-properties-defined-in-local-properties-in-build-gradle

http://stackoverflow.com/questions/21096819/jni-and-gradle-in-android-studio

http://i5on9i.blogspot.kr/2015/02/android-studio-ndk-hello-world.html

https://www.davidlab.net/ko/tech/using-the-android-ndk-with-android-studio-part1/






ArrayAdapter<String>을 이용해 ListView에 String배열 데이터를 넣고
커스텀뷰를 적용한 사례이다.


리스트뷰의 글자크기나 요소간 간격(item height / element height)도 조절할 수 있다..


listView1은 activity_main.xml에서 배치한 리스트뷰의 아이디이다
소스파일(*.java)에서 ListView객체와 String배열을 정의한다
ListView view = (ListView)findViewById(R.id.listView1); 
String[] values = new String[LIST_NUM]; 
for(int i=0; i<LIST_NUM; i++) {
    values[i] = i;
}
그리고 어레이어댑터를 만들어 뷰에 적용.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.my_text_view, values);
view.setAdapter(adapter);

바로 위의 코드에서 my_text_view는 임의로 이름 붙인 커스텀뷰인데, 이제 이것을 만들어야 한다
프로젝트 경로에서 res\layout(메인액티비티 레이아웃이 있는 폴더)에 새로운 xml 파일을 만든다.
이름은 위 코드에서 쓴 것과 같아야 한다.(여기서는 my_text_view.xml)

실제로 적용했었던 코드를 그대로 옮겨보면,
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceSmall"
    android:gravity="center_vertical"
    android:paddingStart="2dip"  //패딩(테두리 여백)
    android:textSize="21sp"  //글자 크기
    android:textColor="#EEEEEE"  //글자색
    android:minHeight="34dp"  //리스트 요소 폭
/>



다음과 같은 레아이웃이 적용된 리스트가 표시된다.

(https://play.google.com/store/apps/details?id=com.zetagate.pitchspeed)



pitching velocity unit converter (mph - kph) 제작일기...



구글플레이에서 다운받기 :

https://play.google.com/store/apps/details?id=com.zetagate.pitchspeed





◎ 레이아웃 설정과정.


→ 메인 액티비티 레이아웃 xml 에서 ListView 배치.


→ String 배열 생성후 값 저장


→  ArrayAdapter<String> 객체 생성. 


→ 객체 생성 시 TextView 레이아웃 리소스가 @android:layout/simple_list_item_1 로 지정되어 있어서

  스타일을 자유롭게 변경 불가..


→ 프로젝트 디렉터리 내 layout폴더에 사용자정의 레이아웃 xml파일 생성 후 TextView레이아웃 정의.

  android:minHeight 으로 간격 조절.


→ 어레이어댑터 생성자에서 데이터(String[])도 역시 지정.


→ ListView객체에서 setAdapter로 어레이어댑터(텍스트뷰 레이아웃과 리스트 데이터) 설정




◎ 데이터 생성과정 (정수(integer)로만 출력되도록 처리).


→ mph 속력 * 1.609344 를 계산하여 소수점 이하 자리를 취하고 det이라 함.


→ det < 1-RATIO/2 일 시 mph속력 하나당 kph속력 하나 출력.


→ 1-RATIO/2 < det < RATIO/2 일 시 mph속력 하나당 kph속력 두 개 출력


→ else  올림 처리하여 kph속력 하나 출력.


제작자 페이지 : http://zetagate.com








1. 우선 Keystore(키스토어)자체가 다른 경우. 당연히 업로드 실패가 뜬다.





2. 그렇다면 같은 키스토어 내에서 Alias가 다른 경우는?



이것 역시 업로드가 제한된다.





3. 패키지 경로가 다른 경우도 역시 실패.






그냥 궁금해서 직접 해봤습니다...











Adobe AIR로 안드로이드 애플리케이션을 만들 때

플래시디벨롭 등에서 adt를 실행하여 디버그모드로 테스트하려고 하면

IP주소를 입력하라는 창이 뜨고 정상적으로 동작하지 않는 경우가 있는데,


USB디버깅을 7936번 포트를 통해서 하므로

adt에서 option에 -listen 7936 이라고 써 주면 디버그모드가 정상적으로 실행된다.




adt -package -target %TYPE%%TARGET% %OPTIONS% %SIGNING_OPTIONS% "%OUTPUT%" "%APP_XML%" %FILE_OR_DIR%

(여기서 OPTIONS 부분. 플래시디벨롭에선 packager.bat 파일에 있음.

 그리고 run.bat에서 android debug 부분을 찾아서

TARGET=-debug
OPTIONS=-listen 7936

위와 같이 설정해 주면 간편하게 할 수 있다.)





안드로이드 킷캣(api 19)이 나온 뒤 이클립스를 업데이트하고

새 프로젝트를 생성하니까 appcompat_v7이 포함되면서 이전에는 없던 문제들이 생긴다.


@android:style/Theme.NoTitleBar

는 실패.(런타임 에러가 난다)


@android:style/Theme.Holo.NoActionBar

는 minSdkVersion이 11이상(안드로이드 3.0 허니콤)일 때만 돼서 실패.


에러내용들을 보면

android:theme을 "@style/AppTheme"로 해야된다고 나오는데

그렇게 설정한 뒤 액티비티의 onCreate() 내에서 requestWindowFeature로 타이틀바를 없애야한다.

setContentView()를 호출하기 전에 해야된다는 것에 유의!


예시)

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);




이렇게 하면 어플 실행 시 타이틀바가 잠깐 보이다가 사라지는데

뭔가 미봉책 같은 느낌...

처음부터 appcompat_v7을 생성되지 않게 하면 기존방식대로 @android:style/Theme.NoTitleBar 으로 되지 않을까 싶은데 아직 해보지는 않았다


appcompat_v7이 생성되지 않게 하는 법은 인터넷으로 검색해보면 쉽게 찾을 수 있다. 






윈도우에서 Android SDK Manager를 실행했는데 실행이 되지 않고 바로 꺼져버린다면

다음과 같은 환경변수를 추가하면 해결될 수 있다.


변수 : JAVA_HOME

값 : JDK(Java Development Kit)가 설치된 디렉터리




1. 내컴퓨터를 우클릭하여 속성 - 고급설정으로 들어간다.






2. JAVA_HOME환경변수로 jdk설치경로를 지정한다.








구성

1. 서비스 실행 시 알림 띄우기

2. 알림을 지워지지 않게 만들기('실행 중' 탭에 띄우기)




1장.


 안드로이드 이전 버전에서는 노티피케이션(Notification)을 띄우기 위해 Notification 인스턴스를 만들어 사용했지만

지금은 Notification.Builder를 통해 생성하도록 권장하고 있다.

여기서는 이전 버전과의 호환성을 위해 android.support.v4.app 패키지의 NotificationCompat.Builder 객체를 사용한다.


 그렇기 때문에 android-support-v4.jar 파일을 프로젝트에 추가해야 하는데

이 파일은 안드로이드sdk 설치 디렉토리 - extras - android - support - v4  경로에 있다.

이 파일을 이클립스 기준으로, 프로젝트속성 - java build path - libraries에 들어가 포함시키면 된다.




 서비스에서 노티피케이션을 띄우기 위한 코드는 서비스의 onStartCommand 함수 내에 작성한다.

먼저 NotificationCompat.Builder 객체를 생성하고, 필수로 SmallIcon과 ContentTitle, ContentText를 지정해 주어야 한다.


(▽ 상단바에 왼쪽편에 있는 아이콘들이 SmallIcon들이다.) 


(▽ "USB가 연결되었습니다"문구가 ContentTitle이고, "컴퓨터로부터 또는 컴퓨터로..."부분이 ContentText이다.) 



그리고 노티피케이션을 터치했을 때 어떤 동작을 할 것인가를 지정해 주는데

여기서는 메인 액티비티인 MainActivity를 실행해 주기로 하였다.


Intent를 만든 뒤 TaskStackBuilder 객체에 추가하고

그것을 바탕으로 TaskStackPendingIntent 객체를 완성한다.

그리고 그 객체를 처음에 만들었던 NotificationCompat.Builder 객체에서 setContentIntent()로 설정.

마지막으로 NotificationManager를 생성하여 notify()시키면 노티피케이션이 뜨게 된다.


코드는 아래와 같다. 


   NotificationCompat.Builder mBuilder =

    new NotificationCompat.Builder(this)

    .setSmallIcon(R.drawable.smallicon)

    .setContentTitle("알림바 실험")

    .setContentText("알림바입니다..");

   

   Intent resultIntent = new Intent(getApplicationContext(),MainActivity.class);

 

   TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

   stackBuilder.addParentStack(MainActivity.class);

   stackBuilder.addNextIntent(resultIntent);

   

   PendingIntent resultPandingIntent =

    stackBuilder.getPendingIntent(

    0,

    PendingIntent.FLAG_UPDATE_CURRENT

    );

   

   mBuilder.setContentIntent(resultPandingIntent);

   

   NotificationManager mNotificationManager =

  (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

 

   mNotificationManager.notify(3452, mBuilder.build());



 NotificationCompat.Builder 객체를 만들 때, 스타일을 설정하는 set메서드들이 NotificationCompat.Builder 반환값을 가지므로

.setSmaillIcon().setContentTitle().setContentText() 와 같이 이어지게 될 수 있다.


 (노티피케이션이 등록될 때 상단바에 메시지가 나타나는 것은 setTicker().로 설정할 수 있다.)

 

 MainActivity라고 되어있는 부분은 노티피케이션을 선택했을 때 실행할 액티비티이며 상황에 맞게 다른 액티비티 이름이 올 수 있다.


 notify()함수에서 3452는 노티피케이션을 관리하기 위한 id값으로 여기서는 임의의 값을 써 둔 것이다.



다른 컨텍스트에서 노티피케이션을 종료해야 할 때는 다시 NotificationManager를 생성하여

아까 지정한 id(3452)를 통해 지울 수 있다. 코드는 다음과 같다.


  NotificationManager mNotificationManager =

   (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

 

  mNotificationManager.cancel(3452); 




2장. 


 안드로이드 운영체제는 시스템 자원이 부족하다든지 하는 경우에 실행 중인 서비스를 끌 수도 있다. (꺼졌다가 다시 켜지기도 한다)

이를 방지하기 위해선 서비스를 포그라운드(Foreground)로 실행해야 한다. 

또한 알림을 지워지지 않고 '실행 중'탭에 놓기 위해서도 역시 포그라운드로 서비스를 실행하면 된다.

서비스를 포그라운드로 실행하려면 노티피케이션을 띄워 주어야 하는데

1장에서 만든 NotificationCompat.Builder 객체를 그대로 사용할 수 있다.

코드는 아래와 같다. (위 코드와 중복되는 부분이 대부분)



    NotificationCompat.Builder mBuilder =

     new NotificationCompat.Builder(this)

     .setSmallIcon(R.drawable.smallicon)

     .setContentTitle("알림바 실험")

     .setContentText("알림바입니다..");

    

    Intent resultIntent = new Intent(getApplicationContext(),MainActivity.class);

  

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

    stackBuilder.addParentStack(MainActivity.class);

    stackBuilder.addNextIntent(resultIntent);

    

    PendingIntent resultPandingIntent =

     stackBuilder.getPendingIntent(

     0,

     PendingIntent.FLAG_UPDATE_CURRENT

     );

    

    mBuilder.setContentIntent(resultPandingIntent);

    

   this.startForeground(3452,mBuilder.build());


1장의 코드와 비교하여 NotificationManager 부분이 없어지고 startForeground()함수를 추가됐다.


노티피케이션을 제거할 때는 아래 코드로 포그라운드를 취소하면 된다.


this.stopForeground(true);




 ====================================================================================================






https://play.google.com/store/apps/details?id=com.podocube.sunglass

화면을 좀더 어둡게 해 주는 어플을 만들어서 구글플레이에 처음으로 올려보았다.

생각만큼 쉽게 업로드되지는 않았다.

올리는 과정을 한번 해보다는 목적으로 해서 어플자체는 완성도가 떨어진다..

제목의 sunglass가 sunglasses가 아닌 이유는 glass가 하나이기 때문(?)







=====================================================================


+ Recent posts