안녕하세요. IT 김군입니다.

 

오늘은 Android 개발 혹은 공부하시는 분들이라면 모두들 기본적으로 하시는 아이콘 변경에 대해서 메모해보도록 하겠습니다.

 

어떻게보면 대표 아이콘은 스토어에서 직관적으로 보여져서 App을 대표하는 마스코트 느낌이기 때문에 많이들 신경쓰실 것 같습니다.

 

하지만 저는 메모장이기 때문에....... 허접하게 IT김군 이름이 들어간 아이콘을 하나 준비하였습니다.

 

우선 아이콘 적용을 위해 적용할 아이콘 이미지를 준비합니다.

 

스토어에 적용되어 보여질 사이즈는 512x512 입니다.

 

저도 메모를 위해 512x512 사이즈의 png 파일을 하나 준비했습니다.

 

이미지가 준비되었다면 다음은 준비된 이미지를 Android Studio에서 프로젝트에 적용해보겠습니다.

 

방법은 굉장히 간단하기 때문에 아래 사진들을 보시면서 차근차근 하시면 쉽게 하실 수 있습니다.

 

 

res에서 마우스 우클릭을 하신 후 New -> Image Asset를 클릭합니다.

 

Image Asset를 클릭하시면 아래와 같은 창이 생성됩니다.

 

 

저는 icon 이름을 ic_main으로 변경했습니다.

 

정확하게 정해진 것이 없기때문에 구분하기 편하신 이름으로 지정하시면 됩니다.

 

아래 Resize의 경우 크기가 조금 안맞는 것 같으면 Resize를 통하여 조절할 수 있습니다.

 

여기까지 완료되었다면 Next를 눌러줍니다.

 

아이콘 사이즈가 512x512로 잘 지정되었죠?

 

Finish를 눌러서 적용해줍니다.

 

여기까지 완료하셨다면 res\mipmap 여러 폴더들에 아래와 같이 제가 적용한 아이콘이 들어가 있을 것입니다.

 

제가 적용한 ic_main이 매우 잘 들어있습니다.

 

그럼 이제 이미지는 넣었고, 이 이미지를 적용해봐야겠죠?

 

그럼 이제 AndroidManifest.xml 파일로 가보도록 하겠습니다.

 

AndroidManifest.xml에서는 아래 두 부분만 수정해주시면 됩니다.

 


android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"

▼ 아래 처럼 변경 ▼

android:icon="@mipmap/ic_main"
android:roundIcon="@mipmap/ic_main_round"

 

위와 같이 변경해주시면 됩니다.

 

못찾으시는 분들을 위해 AndroidManifest.xml 풀 소스를 보여드리겠습니다.

 

 


#### AndroidManifest.xml ####

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_main" ---------------------------------- 이 부분 수정
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_main_round" ----------------------- 이 부분 수정
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

이렇게 두 부분을 수정해주신 후 빌드하시고 적용해보시면 아이콘이 정상적으로 바뀌어 있는 것을 확인하실 수 있습니다.

 

혹시나 저의 메모에 잘못된 부분이 있거나 이해가 잘 안되시는 부분이 있으시다면 댓글 부탁드리겠습니다.

 

요즘 저도 애드센스를 계속 신청해보고 있는데 계속 거절당하고 있습니다.

 

요즘은 거절 이유도 피드백으로 주지 않더군요....

 

왜 거절당하는지 예상되어지는 부분이 있으신 분도 댓글로 알려주시면 감사하겠습니다.

 

다음에는 더 유익한 내용으로 메모해보도록 하겠습니다.

 

도움되셨다면 공감 버튼 한 번씩만 부탁드리겠습니다.

 

감사합니다.

 


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  4개가 달렸습니다.
  1. 머가 그렇게 대단한거 가르쳐 준다고 이미지에 마우스 갔다 대면 흐려지내 에라이 새끼야 퉤
    • 제가 효과넣은게 아니라 티스토리 자체적으로 그렇게 되는겁니다.
      집에 가서 인성부터 더 배우고 오세요^^
      사람이 아니시라서 이제 대응하지 않겠습니다.
  2. 저분은 뭔데 이런걸로 화를내지,, ㅋㅋㅋㅋㅋㅋ웃긴사람이네
    정보 감사합니다~
  3. 감사합니다~

    근데 저거 마지막 Manifest.xml
    수정을 안해도 아이콘 잘 바뀌네요
    업데이트 되서 그런가..?
secret

안녕하세요. IT 김군입니다.

 

오늘은 Android를 개발하신다면 모두 사용하실만한 Multi Permissions에 대해 메모해보도록 하겠습니다.

 

각각 개별로 Permission 요청하는 방법에 대해서는 설명이 잘 나와있는 곳이 많아서 여러 개를 사용하는 것만 메모하겠습니다.

 

우선 오늘도 파일을 나누어서 시작하겠습니다.

 

 

오늘은 패키지 안에 support라는 폴더를 생성했고

그 안에 PermissionSupport.java 파일을 만들었습니다.

 

추후 관리의 편의성을 위해 제 자신만의 방법으로 폴더를 구분하고 파일을 나눈 것이라서

이 방법이 불편하신 분들은 그냥 Activity에 코딩하셔도 상관 없습니다!

 

그럼 PermissionSupport.java의 소스를 먼저 보도록 하겠습니다.

 


// #### PermissionSupport.java ####

package com.itkim.exam.permissionsexam.support;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;

public class PermissionSupport {

    private Context context;
    private Activity activity;

    // 요청할 권한을 배열로 저장해주었습니다.
    private String[] permissions = {
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };

    private List permissionList;

    // 이 부분은 권한 요청을 할 때 발생하는 창에 대한 결과값을 받기 위해 지정해주는 int 형입니다.
    // 본인에 맞게 숫자를 지정하시면 될 것 같습니다.
    private final int MULTIPLE_PERMISSIONS = 1023;

    // 생성자에서 Activity와 Context를 파라미터로 받았습니다.
    public PermissionSupport(Activity _activity, Context _context){
        this.activity = _activity;
        this.context = _context;
    }

    // 허용 받아야할 권한이 남았는지 체크
    public boolean checkPermission(){
        int result;
        permissionList = new ArrayList<>();

        // 위에서 배열로 선언한 권한 중 허용되지 않은 권한이 있는지 체크
        for(String pm : permissions){
            result = ContextCompat.checkSelfPermission(context, pm);
            if(result != PackageManager.PERMISSION_GRANTED){
                permissionList.add(pm);
            }
        }

        if(!permissionList.isEmpty()){
            return false;
        }
        return true;
    }

    // 권한 허용 요청
    public void requestPermission(){
        ActivityCompat.requestPermissions(activity, permissionList.toArray(new String[permissionList.size()]), MULTIPLE_PERMISSIONS);
    }

    // 권한 요청에 대한 결과 처리
    public boolean permissionResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){

        // 우선 requestCode가 아까 위에 final로 선언하였던 숫자와 맞는지, 결과값의 길이가 0보다는 큰지 먼저 체크했습니다.
        if(requestCode == MULTIPLE_PERMISSIONS && (grantResults.length > 0)){
            for(int i=0; i < grantResults.length ; i++){
                //grantResults 가 0이면 사용자가 허용한 것이고 / -1이면 거부한 것입니다.
                // -1이 있는지 체크하여 하나라도 -1이 나온다면 false를 리턴해주었습니다.
                if(grantResults[i] == -1){
                    return false;
                }
            }
        }
        return true;
    }
}

 

해당 Class의 큰 흐름을 보면 이렇습니다.

 

1. 우선 요청할 권한들을 String 배열을 선언하여 넣어주었습니다.

 

2. 요청에 대한 결과값을 확인하기 위해 RequestCode를 Final로 정의해주었습니다. (MULTIPLE_PERMISSIONS)

 

3. checkPermission() 함수를 통해 위에서 배열로 선언한 권한 중 허용되지 않은 권한이 있는지 체크하였습니다.

 

4. requestPermission() 함수에서는 위에서 배열로 선언한 권한에 대해 사용자에게 허용 요청을 하였습니다.

 

5. permissionResult() 함수에서는 요청한 권한에 대한 결과값 판단하도록 하였습니다.

 

주석도 제 나름대로 상세하게 달아놓아서 이해가 잘 안되시는 분들은 주석을 참고하셔도 될 것 같습니다.

 

그럼 이제 이 클래스를 Activity에서 활용하는 방법에 대해서 보도록 하겠습니다.

 

 


// #### MainActivity.java ####

package com.itkim.exam.permissionsexam;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Build;
import android.os.Bundle;

import com.itkim.exam.permissionsexam.support.PermissionSupport;

public class MainActivity extends AppCompatActivity {

    // 방금 전 만들었던 클래스를 선언해줍니다.
    private PermissionSupport permission;

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

        permissionCheck();
    }

    // 권한 체크
    private void permissionCheck(){

        // SDK 23버전 이하 버전에서는 Permission이 필요하지 않습니다.
        if(Build.VERSION.SDK_INT >= 23){
            // 방금 전 만들었던 클래스 객체 생성
            permission = new PermissionSupport(this, this);

            // 권한 체크한 후에 리턴이 false로 들어온다면
            if (!permission.checkPermission()){
                // 권한 요청을 해줍니다.
                permission.requestPermission();
            }
        }
    }

    // Request Permission에 대한 결과 값을 받아올 수 있습니다.
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        // 여기서도 리턴이 false로 들어온다면 (사용자가 권한 허용을 거부하였다면)
        if(!permission.permissionResult(requestCode, permissions, grantResults)){
            // 저의 경우는 여기서 다시 Permission 요청을 걸었습니다.
            permission.requestPermission();
        }
    }
}

 

MainActivity에서 활용법을 보시면 굉장히 간단합니다.

 

우선 위에서 만들었던 Class를 활용하기 위해 객체를 생성해준 후 check / request를 통해 권한을 요청했습니다.

 

그리고 아래 보시면 onRequestPermissionResult 가 있는데 이 부분은

 

Ctrl + O 단축키를 통해 오버라이드 하실 수 있습니다.

 

요청한 권한에 대한 결과 값을 얻어올 수 있는 함수입니다.

 

위 MainActivity까지 완료하셨다면 여러 개의 권한을 한 번에 요청할 수 있는 Multi Permissions 완성입니다!

 

혹시나 해당 메모에서 잘못된 부분이나 이해하시기 어려운 부분이 있으시다면 댓글로 달아주세요.

 

오늘의 메모는 여기서 마무리 하도록 하겠습니다.

 

감사합니다.


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  0개가 달렸습니다.
secret

안녕하세요. IT 김군입니다.

 

오늘은 SQLite 초간단 예제!를 메모해보도록 하겠습니다.

 

우선 프로젝트 진행하시다보면 Activity에 모든 코딩을 하시지는 않으시라 생각됩니다!

 

그래서 2개의 Java Class를 생성 후 Activity에서 사용하는 방법으로 진행해보도록 하겠습니다.

 

우선 제가 만들 테이블은 간단하게

 

(이름, 성, 핸드폰 번호)를 칼럼으로 갖는 테이블을 만들고 사용해보도록 하겠습니다.

 

저는 아래 사진과 같이 패키지 내부에 SQLite라는 폴더를 생성한 후

 

SQLiteControl / SQLiteHelper 두 개의 Java 파일을 생성하였습니다.

 

위와 같이 생성하셨다면 SQLiteHelper.java 파일을 먼저 코딩해보도록 하겠습니다.

 

우선 SQLiteHelper에 아래 사진과 같이 android.database.sqlite.SQLiteOpenHelper를 상속해줍니다.

 

 

그럼 위와 같이 빨간 밑줄이 쫘~~악! 그어지는데요.

 

몇 가지 Function들을 오버라이드 해주어야 합니다.

 

Ctrl + O 키를 누르면 Override 할 수 있는 함수들이 쭉~ 나올 것입니다.

 

여기서 아래 사진과 같이 생성자, onCreate, onUpgrade를 포함해줍니다.

 

 

해당 함수들을 모두 포함하고 OK를 누르면 자동으로 입력되며,

 

아래와 같이 빨간 줄이 사라집니다!

 

 

그럼 이제 소스를 살펴보겠습니다.

 

먼저 SQLiteHelper.java를 모두 코딩한 소스입니다.

 

SQLiteHelper에서는 DB를 생성, Open 및 버전 Update에 대한 내용을 편리하게 도와주는 Class 입니다.


#### SQLiteHelper.java ####

package com.itkim.exam.sqliteexam.SQLite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import androidx.annotation.Nullable;

public class SQLiteHelper extends android.database.sqlite.SQLiteOpenHelper{

    // 저는 나중에 수정할 때를 대비하여 final 선언을 하였지만 굳이 이렇게 안하셔도 괜찮습니다.
    public final String TABLE_NAME = "itkimtable";
    public final String FIRST_NAME = "f_name";
    public final String LAST_NAME = "l_name";
    public final String PHONENUM = "phoneNum";

    public SQLiteHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        // Table 생성하는 Query
        // ( if not exists ) 만약 존재하지 않으면 생성
        String create_query = "create table if not exists " + TABLE_NAME + "("
                + FIRST_NAME + " text not null , "
                + LAST_NAME + " text , " // not null을 쓰시지 않으실 때는 이렇게 선언합니다.
                + PHONENUM + " text primary key);"; // primary key는 이렇게 선언합니다.

        // 위 Create Query로 Table을 생성해줍니다.
        sqLiteDatabase.execSQL(create_query);
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        // SQLite에 대해 설정한 버전을 올렸을 때

        // 기존 테이블 Drop 해준 후
        String drop_query = "drop table " + TABLE_NAME + ";";
        sqLiteDatabase.execSQL(drop_query);

        // onCreate를 호출해서 Table 다시 생성
        onCreate(sqLiteDatabase);
    }
}

 

 

그럼 다음으로 SQLiteHelper.java 소스를 살펴보도록 하겠습니다.


#### SQLiteControl.java ####

package com.itkim.exam.sqliteexam.SQLite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;

public class SQLiteControl {

    SQLiteHelper helper;
    SQLiteDatabase sqlite;

    // 생성자
    public SQLiteControl(SQLiteHelper _helper){
        this.helper = _helper;
    }

    // DB Insert
    public void insert(String _firstName, String _lastName, String _phoneNum){
        sqlite = helper.getWritableDatabase();
        ContentValues values = new ContentValues();

        values.put(helper.FIRST_NAME, _firstName);
        values.put(helper.LAST_NAME, _lastName);
        values.put(helper.PHONENUM, _phoneNum);

        sqlite.insert(helper.TABLE_NAME, null, values);
    }

    // DB Select
    public String[] select(){
        sqlite = helper.getReadableDatabase();
        // 커서 사용
        Cursor c = sqlite.query(helper.TABLE_NAME, null, null, null,null,null,null);

        // 칼럼 정보를 배열에 넣고
        String[] columnName = {helper.FIRST_NAME, helper.LAST_NAME, helper.PHONENUM};

        // 칼럼 정보와 길이가 같은 배열을 생성 후
        String[] returnValue = new String[columnName.length];

        // 생성한 배열에 데이터를 받아줍니다.
        while(c.moveToNext()){
            for(int i=0 ; i<returnValue.length; i++){
                returnValue[i] = c.getString(c.getColumnIndex(columnName[i]));
                Log.e("DB Select : ",i + " - "+returnValue[i]);
            }
        }
        // 커서를 사용 후에 꼭 닫아줍시다!
        c.close();
        return returnValue;
    }

    // DB Update
    public void update(String _key, String _value, String _phoneNum){
        sqlite = helper.getWritableDatabase();

        ContentValues value = new ContentValues();
        value.put(_key, _value);
        // 제가 phoneNum를 사용한 이유는 포스팅하는 예제 Table의 Primary Key가 phoneNum 이기 때문입니다.
        sqlite.update(helper.TABLE_NAME, value, "phoneNum=?", new String[]{_phoneNum});
    }

    // DB Delete
    public void delete(String _phoneNum){
        sqlite = helper.getWritableDatabase();
        // 제가 phoneNum를 사용한 이유는 포스팅하는 예제 Table의 Primary Key가 phoneNum 이기 때문입니다.
        sqlite.delete(helper.TABLE_NAME, "phoneNum=?", new String[]{_phoneNum});
    }

    // SQLite Close
    public void db_close(){
        sqlite.close();
        helper.close();
    }
}

 

위와 같습니다.

주석을 상세하게 달아놓는다고 노력하긴 했는데 부족한지 모르겠습니다.

 

그럼 이제 위 두 Class를 활용하여 DB를 사용해보도록 하겠습니다.

 

DB를 실질적으로 사용하는 MainActivity의 소스입니다.

 

 


#### MainActivity.java ####

package com.itkim.exam.sqliteexam;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import com.itkim.exam.sqliteexam.SQLite.SQLiteControl;
import com.itkim.exam.sqliteexam.SQLite.SQLiteHelper;

public class MainActivity extends AppCompatActivity {

    SQLiteHelper helper; // 헬퍼 선언
    SQLiteControl sqlite; // 실제로 SQLite를 활용할 Class를 선언합니다.

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

        // DB를 생성 및 Open합니다.
        helper = new SQLiteHelper(
                MainActivity.this, // context
                "dbFileName.db", // DB 파일 이름을 적어주시면 됩니다.
                null, // Factory
                1 // 현재 생성하는 DB의 버전을 설정합니다.
        );

        /*
            제가 SQLiteControl에 helper를 파라미터로 넣어준 이유는 파일을 나누어서 관리하기 위함입니다.
            그냥 Activity에서 모든 작업을 하고 싶으시면 이렇게 나누시지 않아도 괜찮습니다.
         */
        sqlite = new SQLiteControl(helper);

        dbTest();
    }

    private void dbTest(){
        // DB Insert를 하고 Select로 확인합니다.
        dbInsert();
        dbSelect();

        // DB Update를 하고 Select로 확인합니다.
        dbUpdate();
        dbSelect();

        // DB Delete를 하고 닫아줍니다. (DB를 사용 후에는 꼭 닫는 습관을 들이시는게 좋습니다!)
        dbDelete();
        sqlite.db_close();
    }

    private void dbInsert(){
        // Insert 하려는 정보를 파라미터로 넘겨주기만 하면 Insert 됩니다.
        sqlite.insert("군", "김", "010-0000-0000");
    }

    private void dbSelect(){
        // 아까 SQLiteControl에서 배열로 넘겨주었기 때문에 sqlite.select()를 배열로 받아줍니다.
        String[] selectData = sqlite.select();

        // 배열로 받은 정보를 로그로 확인합니다.
        for(int i=0; i>selectData.length; i++){
            Log.i("@@ Select DB : ", selectData[i]);
        }
    }

    private void dbUpdate(){
        // update 해야 할 column명, 변경할 값, where조건 이지만 간단 예제이기때문에 primary Key를 사용했습니다.
        sqlite.update(helper.FIRST_NAME, "김군", "010-0000-0000");
        sqlite.update(helper.LAST_NAME, "IT", "010-0000-0000");
    }

    private void dbDelete(){
        // delete 해야 할 정보 primary Key를 파라미터로 전달
        sqlite.delete("010-0000-0000");
    }
}

 

위와 같이 진행했을 시 결과 값은 아래와 같습니다.

 

 

처음에 군, 김, 010-0000-0000 이라는 정보를 Insert 후 Select한 정보가 위 3줄입니다.

 

그리고 "군 -> 김군" 으로 "김 -> IT"로 Update 후 Select한 정보가 아래 3줄입니다.

 

혹시나 보시고 어려운 부분이나 보시기 불편한 부분 있으시면 꼭 댓글로 저에게 가르침을 부탁드립니다.

 

혹은 반대로 정말 도움이 많이 되셨다면 공감 한 번 씩만 부탁드리겠습니다.

 

그럼 오늘은 여기까지 메모해보도록 하겠습니다.

 

다들 굿밤되세요!


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  0개가 달렸습니다.
secret

안녕하세요. IT 김군입니다.

 

오늘은 AAR 확장자로 되어있는 Library를 추가하는 방법에 대해 알아보도록 하겠습니다.

 

우선 제가 오늘 포스팅을 위해 준비한 AAR 파일은 Android Beacon Library 입니다.

 

https://altbeacon.github.io/android-beacon-library/

 

Android Beacon Library

The leading library for detecting beacons on Android. What Does This Library Do? It allows Android devices to use beacons much like iOS devices do. An app can request to get notifications when one or more beacons appear or disappear. An app can also reques

altbeacon.github.io

연습용으로 필요하시다면 위 URL에서 다운로드 받으실 수 있습니다.

 

그럼 시작해보도록 하겠습니다.

 

우선 아래 파일이 제가 오늘 준비한 Library AAR 파일입니다.

 

 

1. 이 파일을 사용할 프로젝트에 있는 Libs 폴더에 넣어줍니다.

 

 

 

2. 해당 Libs 폴더에 Drag&Drop 으로 끌어다가 넣어주시면 아래와 같은 창이 생성됩니다.

 

 

3. 네 그럼 우리가 제일 잘하는 OK 버튼 누르기를 시전하면 아래와 같이 추가됩니다.

 

 

4. 파일이 정상적으로 libs 폴더에 추가되었다면 build.gradle 파일을 실행합니다.

(여기서 build.gradle 파일은 app 폴더에 속하여 있는 build.gradle 파일입니다.)

 

 

● 아래 사진 참고

 

5. 해당 파일을 열어서 아래 내용을 추가해줍니다.

 


repositories {
	flatDir{
    	dirs 'libs'
    }
}

implementation name: 'android-beacon-library-2.16.2', ext: 'aar'

 

implementation의 경우

implementation name: '확장자를 제외한 파일명', ext: 'aar'

공식으로 적어주시면 되겠습니다!

 

근데 이걸 어디에 추가하냐고요....??

build.gradle 풀소스는 아래와 같습니다.

 

추가라고 주석 달려있는 부분에 맞추어 추가해주시면 됩니다.

 


apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.1"
    defaultConfig {
        applicationId "package Name"
        minSdkVersion 28
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

// 추가 부분 Start
repositories {
    flatDir {
        dirs 'libs'
    }
}
// 추가 부분 End

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation name: 'android-beacon-library-2.16.2', ext: 'aar' // 추가 AAR Implementation
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

 

해당 부분을 추가해주시면 아래 사진과 같이 우측 상단에 Sync Now가 나옵니다.

 

 

6. 네 망설임 없이 Sync Now 바로 눌러주면 Sync이 진행되며 정상적으로 AAR 파일을 사용할 수 있습니다.

 

아래는 제가 추가한 Beacon Library AAR 파일을 import 한 모습입니다.

 

 

AAR 추가하기 참 쉽죠?

 

글로 풀고 일일이 캡쳐해서 올리려니 이게 시간이 더 걸리네요...ㅠㅠ

 

나중에 제가 기억 못할 때를 위해 열심히 적어봤습니다.

 

혹시나 도움되셨다면 아래 공감 버튼 꼭 좀 부탁드리겠습니다.

 

그럼 다음 편에서 찾아뵙겠습니다.

 

굿밤!


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  0개가 달렸습니다.
secret

안녕하세요. IT 김군입니다.

제 블로그 메모장에 근 1년반만에 글을 적는 것 같네요...

이번에 또 오랜만에 Android 개발 파트를 맡아 진행하게 되다보니 예전에 했던 내용들을 적어놓지 않아

하나도 기억이 안나더군요....

 

그래서 이제는 열심히 적어볼까 합니다.

우선 오랜만에 Android로 돌아오다보니 Google의 공식 지원언어가 Kotlin으로 채택되었더라구요.

하지만 저에게 긴 러닝커브가 주어지지 않아 그나마 조금이라도 봤던 Java로 진행합니다.

저도 Java나 Android에 대한 깊은 지식이 있는게 아니기때문에 잘못된 부분 있으면 댓글 부탁드립니다.

 

서론이 길었네요.

오늘은 Custom ActionBar 만든 후 좌우에 생기는 공백을 지우는 방법을 적어보겠습니다.

 

1. Custom Actionbar 관련한 파일을 생성해줍니다.

 

1-1.\customVeiw\CustomActionBar.java 생성

(저의 경우는 그냥 제가 편해서 폴더 구분한거라 굳이 안하셔도 상관없습니다.)

 

1-2. \layout\custom_actionbar.xml 생성

 

1-3. logo.png

(Custom ActionBar에 넣을 Image를 대충 하나 준비하였습니다.)

 

 

 

이제 가장 먼저 \layout\custom_actionbar.xml 의 소스를 먼저 살펴보겠습니다.


#### custom_actionbar.xml ####

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:background="#000000">

    <ImageView
        android:id="@+id/iv_logo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/logo"
        android:layout_gravity="center_vertical|center_horizontal"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        />
</LinearLayout>

 

custom_actionbar.xml 에서는 LinearLayout을 사용했습니다. (제가 LinearLayout 찬양이라........)

여기서는 사실 큰 작업을 한 건 없습니다.

그냥 background 색상을 지정해주고 layout을 모두 센터로 지정해주었습니다.

 

 

다음은 \customView\CustomActionBar.java 의 소스를 살펴보겠습니다.


#### CustomActionBar.java ####

package com.itkim.exam.customactionbar.customView;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import com.itkim.exam.customactionbar.R;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;

public class CustomActionBar {

    private Activity activity;
    private ActionBar actionBar;

    public CustomActionBar(Activity _activity, ActionBar _actionBar){
        this.activity = _activity;
        this.actionBar = _actionBar;
    }

    public void setActionBar(){
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(false);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setDisplayShowHomeEnabled(false);

        View mCustomView = LayoutInflater.from(activity)
        					.inflate(R.layout.custom_actionbar, null);
        actionBar.setCustomView(mCustomView);
    }
}

 

CustomActionBar.java를 살펴보면 우선

1. ActionBar를 Custom해서 사용할 Activity에 대한 정보를 생성자에서 파라미터로 받아 초기화해줍니다.

2. setActionBar Function을 통해 기존 ActionBar들은 보이지 않게 설정해주고 Custom ActionBar를 등록하여 줍니다.

 

 

 

다음은 MainActivity.java를 살펴보도록 하겠습니다.


#### MainActivity.java ####

package com.itkim.exam.customactionbar.activity;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.itkim.exam.customactionbar.R;
import com.itkim.exam.customactionbar.customView.CustomActionBar;

public class MainActivity extends AppCompatActivity {

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

        setActionBar();
    }

    private void setActionBar(){
        // 커스텀 액션바 적용
        CustomActionBar ca = new CustomActionBar(this, getSupportActionBar());
        ca.setActionBar();
    }
}

MainActivity.java에서도 특별한건 없습니다.

그냥 아까 만들었던 CustomActionBar의 객체를 생성해주었고 Activity와 현재의 Actionbar정보를 넘겨주었습니다.

 

여기까지 진행하시면 짠! Custom ActionBar가 적용됩니다.

 

음....... 회사에서 했을 때는 아래 사진과 같이 공백이 생겼는데 집에서 포스팅하면서 해보니 왜 잘되는지 모르겠군요......

 

우선 아래 사진 보겠습니다.

 

 

분명 회사에서 했을 때는 저기 빨간 박스 부분에 공백이 생겼는데요....

 

일단 생겼다는 가정하에 진행해보도록 하겠습니다.

 

저기에 공백이 생기면 아까 작성했던 CustomActionBar.java에 4줄만 추가해주시면 됩니다.

 


#### CustomActionBar.java ####

package com.itkim.exam.customactionbar.customView;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.itkim.exam.customactionbar.R;

public class Custom_ActionBar extends AppCompatActivity {

    private Activity activity;
    private ActionBar actionBar;

    public Custom_ActionBar(Activity _activity, ActionBar _actionBar){
        this.activity = _activity;
        this.actionBar = _actionBar;
    }

    public void setActionBar(){
        actionBar.setDisplayShowCustomEnabled(true);
        actionBar.setDisplayHomeAsUpEnabled(false);
        actionBar.setDisplayShowTitleEnabled(false);
        actionBar.setDisplayShowHomeEnabled(false);

        View mCustomView = LayoutInflater.from(activity).inflate(R.layout.custom_actionbar, null);
        actionBar.setCustomView(mCustomView);

        // Custom ActionBar 생성하면 양쪽에 공백이 생기는데 이 공백을 채우기 위해 아래 4줄 적용
        Toolbar parent = (Toolbar)mCustomView.getParent();
        parent.setContentInsetsAbsolute(0,0);
        ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT);
        actionBar.setCustomView(mCustomView, params);
    }
}

 

위 주석에 있는 것처럼 아래 4줄만 추가해주시면 정상적으로 작동합니다.

 

 


// Custom ActionBar 생성하면 양쪽에 공백이 생기는데 이 공백을 채우기 위해 아래 4줄 적용
        Toolbar parent = (Toolbar)mCustomView.getParent();
        parent.setContentInsetsAbsolute(0,0);
        ActionBar.LayoutParams params = new ActionBar.LayoutParams(ActionBar.LayoutParams.MATCH_PARENT, ActionBar.LayoutParams.MATCH_PARENT);
        actionBar.setCustomView(mCustomView, params);

 

여기까지 끝!

 

도움이 되셨다면 공감버튼 한 번만 부탁드리겠습니다.

 

저도 Android / Java에 대한 지식이 많이 부족하기에 잘못된 부분이 있다면 댓글로 꼭 알려주세요.

 

감사합니다.

 


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  7개가 달렸습니다.
  1. MainActivity.java에서 getSupportActionBar()를 넣으면 빨간줄이 생깁니다.
  2. 댓글 달아 주신거 보고

    import androidx.appcompat.app.ActionBar; 로 바꾸고
    CustomActionBar.java에서
    public CustomActionBar(Activity activity, ActionBar actionBar){
    this.activity = activity;
    this.actionBar = actionBar;
    }

    public CustomActionBar(MainActivity activity, androidx.appcompat.app.ActionBar supportActionBar) { // 일단 잘 안됨
    this.activity = activity;
    this.actionBar = supportActionBar;
    }
    하니까 빨간줄은 없는데 막상 실행하려니까
    앱이 바로꺼지면서 아래와 같이 에러 로그가 찍히네요

    2020-03-11 13:29:09.053 1773-2454/? E/GnssHAL_GnssInterface: gnssSvStatusCb: a: input svInfo.flags is 8
    2020-03-11 13:29:09.053 1773-2454/? E/GnssHAL_GnssInterface: gnssSvStatusCb: b: input svInfo.flags is 8
    2020-03-11 13:29:09.098 10153-10183/? I/MicroDetectionWorker: #startMicroDetector [speakerMode: 0]
    2020-03-11 13:29:09.100 10153-10183/? W/ErrorReporter: reportError [type: 211, code: 393244, bug: 0]: errorCode: 393244, engine: 0
    2020-03-11 13:29:09.102 10153-10183/? I/MicroDetector: Keeping mic open: false
    2020-03-11 13:29:09.103 10153-10183/? I/MicroDetectionWorker: #onError(false)
  3. 아 월요일부터 시작된 고통을 끝내게 해주셨습니다. 정말 감사합니다.
  4. 학생 123 2020.06.19 23:37
    ActionBar bar = getSupportActionBar();
    이렇게 사용하였을때 이 한줄이 전체적으로 빨간줄이 뜹니다
    import androidx.appcompat.app.AppCompatActivity;
    되어있습니다

    마우스를 가져다대면 이렇게 뜹니다
    incompatible types.
    Requlred: android.app.ActionBar
    Found: androidx.appcompat.app.ActionBar

    Change varlable 'bar' type to 'androidxappcompat.app.ActionBar' Alt+Shift + Enter
    More actions... Alt + Enter
secret

안녕하세요 IT김군입니다. 오늘은 안드로이드 apk를 디컴파일하는 방법에 대해 알아보겠습니다.


저는 보통 배포하기 전에 proguard로 난독화를 한 후에 apk를 생성하고 그 apk가 난독화가 잘 되었는지 확인하기 위해 디컴파일을 한 번 하여 확인합니다.


안드로이드 apk 파일 디컴파일 하는 방법은


1. 우선 디컴파일에 필요한 파일들을 다운로드 받아야 합니다.


- dex2jar 다운로드





- java-decompiler/jd-gui 다운로드 (플랫폼에 맞는 파일 형식으로 다운로드 하시면 됩니다.)




그 다음 둘 다 압축을 풀어주시고, 위 dex2jar 압축해제했던 폴더에 복호화 할 apk를 넣어줍니다.




저는 테스트로 abc_test.apk 라는 이름으로 진행해보겠습니다.


그 다음 현재 폴더에서 command 창을 열어주신 후 아래와 같이 입력해주세요.



d2j-dex2jar.bat ApkName.apk


해당 명령어를 입력하면 해당 폴더에 아래와 같이 jar 파일이 생깁니다.





아까 다운로드 받았던 gui decompiler의 압축을 풀어서 exe를 실행한 후 해당 apk 파일을 열어주면 디컴파일이 되어서 소스가 보이게 됩니다.


궁금하신 사항 있으시면 댓글 달아주세요.


감사합니다.



WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  1개가 달렸습니다.
  1. 어플정지 2020.02.10 18:54
    안녕하세요 글쓴이님! 다름이 아니라 루팅된 단말기에서 xposed 모듈 앱을 통하여 단말기 고유번호, mac주소, 전화번호등을 임의로 변경 했을 때 어플 서버 쪽에서 이런 임의로 변경된 데이터를 수집하게끔 수정 하는 기술을 사례금 드리고 좀 배우고 싶은데 가능할까요? 그외에 루팅을 허용 하게끔 수정 하는법도 필요 합니다 사례금은 꼭 드리겠습니다 부탁드립니다 조금 간절 해서요ㅠㅠ

    https://open.kakao.com/o/smSGYUVb

    luispigo615@naver.com
secret

안녕하세요. IT김군입니다.


Android 빌드 또는 실행 시 


Error : INSTALL_FAILED_UPDATE_INCOMPATIBLE


위와 같은 Error가 발생한다면 해결방법은 두가지입니다.


1. 테스트 디바이스 혹은 에뮬레이터에서 현재 빌드하는 프로젝트와 같은 패키지명을 가진 App이 있는지 확인하여 삭제.


2. 프로젝트 Clean


웬만해서는 1번에서 다 해결되실거라고 봅니다.


궁금하신점은 댓글 부탁드립니다.


감사합니다.


WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  0개가 달렸습니다.
secret

안녕하세요. 소프트웨어 IT 김군입니다.


오늘은 Mac OS X에서 Android Studio 설치 및 Android 환경 세팅하는 법에 대해 포스팅을 해보도록 하겠습니다.


먼저 Android Studio 다운로드 경로는 https://developer.android.com/studio/index.html 입니다.


위 링크 페이지에 접근하셔서 아래 사진과 같이 다운로드를 진행합니다.








아래 사진의 네모박스처럼 약관에 동의하고 다운로드를 진행합니다.






위 사진과 같이 다운로드를 받은 후 다운로드 받은 파일을 실행하면 아래와 같이 화면이 나옵니다.


아래 화면에서 화살표와 같이 드래그를 해주시면 정상적으로 설치가 진행됩니다.


설치는 원하시는 경로가 따로 없다면 다음, 다음을 눌러주시면 됩니다.






설치가 완료된 후 Android Studio를 실행하면 아래와 같은 화면이 나오는데요.


아래 화면과 같이 나오면 우측 하단의 Configure를 클릭하여 SDK Manager로 들어갑니다.





그 후 SDK Manager에서 원하시는 버전을 체크 후 Apply 혹은 OK를 누르시면 SDK 설치를 진행합니다.





SDK까지 설치하셨으면 기본적인 세팅은 완료입니다. 

Emulator에 대한 설치도 있지만 매우 간단하여 넘어가도록 하겠습니다.


오늘 시간이 너무 늦어 여기까지 간략하게 하고, 다음번에는 좀 더 상세히 포스팅하도록 하겠습니다.


감사합니다.




WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  0개가 달렸습니다.
secret

안녕하세요. 소프트웨어 IT김군입니다.


오늘은 MAC OS X에서 Java를 설치하는 법에 대해 포스팅을 해보겠습니다.


우선 JAVA를 다운로드 받기 위해 Oracle 페이지로 이동합니다.


Download : http://www.oracle.com/technetwork/java/javase/downloads/index.html


해당 페이지에 들어가시면 아래와 같은 화면을 보실 수 있어요!




포스팅하는 현재는 Java가 9버전까지 나왔지만 저는 개발의 호환성으로 인해 8버전을 사용합니다.


8버전을 사용하실 분은 스크롤을 조금 아래로 내리셔서 아래 사진의 빨간박스를 클릭하시면 됩니다.


다운로드 받는 파일은 Java SE (Standard Edition) 입니다.






MAC OS X는 64bit 밖에 없으니 아래 사진과 같이 'Accept License Agreement'를 체크해주신 후 macOS 용을 다운로드 받으시면 됩니다.




다운로드 받으신 후에는 다운로드 받은 파일을 더블클릭해서 열어주신 후 다음, 다음을 누르면 설치됩니다.


이제 설치는 모두 끝나셨을 것이라 보고 다음 단계로 넘어가보도록 하겠습니다.


Java를 설치하신 후 Windows OS에서 처럼 환경변수를 설정해줘야 합니다.


MAC OS X에서 'control + space'를 누르면 실행창이 나오죠?


거기서 terminal을 입력해주신 후 엔터를 눌러줍니다.







제꺼는 제가 설정을 바꿔서 검은 화면에 초록 글씨로 나오는데 

아마 처음 켜시는 분들이나 설정을 바꾸지 않으신 분들은 하얀화면에 검은글씨로 나올거에요!


처음 터미널을 실행했을 떄의 경로는 '~' 경로로 되어 있는데요.

해당 경로에서


ls -al

위 처럼 입력하여 줍니다.


그러면 아래와 같이 파일들이 주르륵 나올텐데요.


환경변수 설정 시 사용해야 될 파일은 아래 빨간 사각형에 있는 .bash_profile 입니다.




다시 터미널에 아래와 같이 입력합니다.


vi .bash_profile


그럼 vi 편집기 기능으로 .bash_profile이 열리게 됩니다.


vi 편집기는 처음 들어갔을 때는 '보기 모드'이며, 소문자 i를 눌러주게되면 편집모드로 변경되어 작성하실 수 있습니다.


저희는 i를 눌러 아래와 같이 적어보겠습니다.



위 사진에 나온 경로는 제 JAVA 설치 경로입니다. 다른 곳에 설치하신 분은 경로가 다를 수 있으니 확인 후 작성해주세요.


위와 같이 작성을 다 해주시고 엔터를 눌러 아래줄로 내려가서 아래 사진과 같이 작성해주시면 됩니다.



작성을 모두 완료하신 후에는 현재 작성하느라 '편집 모드'로 들어가져있던 vi 편집기에서 esc를 누르게 되면 다시 보기모드로 바뀌는데요.


esc를 눌러 '보기 모드'로 나오신 후 : (Shift + ;)를 눌러주시면 나가기 모드입니다.


나가기 모드에서 wq를 치신 후 엔터를 쳐주시면 저장이 완료됩니다.


w : 저장하기, q : 나가기 / wq : 저장하고 나가기 / 혹시 wq가 안되시는 분들은 wq!를 치고 엔터를 쳐주세요.


그럼 vi 편집기에서 빠져나오게 될텐데요.


빠져나온 후 터미널에서 마지막 작업으로 아래와 같이 쳐주시면 됩니다.


source .bash_profile


이렇게 해주시면 모든 설정이 완료됩니다.


환경변수가 제대로 적용이 되었는지 확인하는 방법은 터미널에서 아래와 같이 쳐주시면 되며,


echo $PATH


모든 설정을 완료했기 때문에 아래와 같이 터미널에 입력하면

javac -version

자바 버전이 나올 것 입니다.


그럼 다음에는 다른 포스팅으로 찾아뵙겠습니다.


감사합니다.



WRITTEN BY
IT김군
S/W 개발자 김군의 메모장

트랙백  0 , 댓글  2개가 달렸습니다.
  1. 개발자1 2019.04.28 21:49
    source .bash_profile 입력하면 -bash: .bash_profile: No such file or directory 이렇게 뜨는데 왜그럴까요.. 그리고 ls -al 치면 bash_profile 이 목록에 없습니다.. 이게 문제인가요?
    • 죄송합니다. 답변이 너무 늦었네요 ㅠㅠ
      'cd ~'를 입력하신 후 다시 'ls -al'을 해보시면 나올 것 같습니다!
secret