안녕하세요. 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 개발자 김군의 메모장

,

안녕하세요. 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 개발자 김군의 메모장

,

안녕하세요. 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 개발자 김군의 메모장

,

안녕하세요. 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 개발자 김군의 메모장

,

안녕하세요. 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 개발자 김군의 메모장

,

Jar로 압축하는 방법


Windows - cmd

MAC OS X - terminal


각 OS에 맞게 실행한 후 압축할 파일이 있는 폴더로 이동하여 아래와 같이 입력.

jar cvf FileName.jar



Jar를 압축해제하는 방법


Windows - cmd

MAC OS X - terminal


각 OS에 맞게 실행한 후 압축을 해제할 jar파일이 있는 폴더로 이동하여 아래와 같이 입력.

jar xvf JarName.jar


명령어(jar) 옵션(cvf / xvf) 파일명(FileName / JarName.jar)


아래는 Jar의 옵션입니다.


c(Create) : 새로운 JAR 파일을 생성하기 위해 사용한다.


t(Table) : JAR 파일의 목록을 나열하기 위해 사용한다.


u(Update) : 기존의 JAR 파일을 수정하기 위해 사용한다.


x(eXtract) : JAR 파일로부터 파일을 추출할 때 사용한다.


v : 압축률 및 생성일시 등의 자세한 정보를 보여준다.


f : jar 파일의 이름을 지정할 경우에 사용한다.


m : 지정된 manifest 파일로부터 menifest 정보를 JAR 파일 내에 포함시켜 준다.


0 : zip 형식의 압축을 하지 않고, 단지 파일을하나로 묶어주기만 한다.


M : menifest 파일을 생성하지 않는다.


-C : 지정된 디렉토리의 파일들을 포함시킨다.




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

,

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


저번 휴대전화번호 정규식 / 체크디지트에 이어 차량번호 정규식 / 체크디지트를 가볍게 만들어 봤습니다.


C# / .NET은 구글링을 해도 정규식이 잘 나오지 않아 직접 만들어 써야하는군요...........ㅠㅠ


완벽하지는 않지만 이 정도면 되겠다 싶으신 분들이 사용하시면 될 것 같습니다.


제가 만든 정규식은 아래와 같습니다.


@"(([0-9]{2}[가-힣]{1}[0-9]{4}|[가-힣]{2}[0-9]{2}[가-힣]{1}[0-9]{4}))"


'00가0000' 혹은 '지역00가0000' 두 가지 경우의 차량번호를 체크합니다.


'00가0000'의 경우는 앞에 2자리는 0~9까지의 숫자가 들어올 수 있으며, 3번째 자리는 한글만 들어올 수 있고, 나머지 4자리도 0~9까지 숫자만 들어올 수 있게 처리하였습니다.


그리고 | 를 활용하여 or로 지역00가0000의 경우까지 대처하도록 하여


'지역00가0000'의 경우에는


앞 2자리는 한글, 3~4번째는 숫자, 5번째는 한글, 마지막 4자리는 숫자만 들어올 수 있도록 처리하였습니다.


빠르게 만들어서 사용하려다보니 받침 등을 써도 체크하지 못하는 부분과 0000 이런 숫자가 들어갈 수 있는 부분에 대해서는 처리가 되지 않았지만,


이 정도만 사용해도 괜찮다 하시는 분들만 참고해주세요~


아래는 제가 코딩한 활용 방안입니다.


// 차량번호 체크
private void carNumCheck()
{
    string carNum = "11가1111";

    if (carNum.Length == 7 || carNum.Length == 9)
    {
        Regex regex = new Regex(@"(([0-9]{2}[가-힣]{1}[0-9]{4}|[가-힣]{2}[0-9]{2}[가-힣]{1}[0-9]{4}))");
        Match m = regex.Match(carNum);
        if (m.Success)
        {
            MessageBox.Show("@@ Success");
        }
        else
        {
            MessageBox.Show("@@ Fail");
        }
    }
    else
    {
        MessageBox.Show("자릿 수 맞지 않음.");
    }
}


잘못된 부분이나 궁금하신 점 댓글주세요.


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


감사합니다.




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

,

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


핸드폰 번호를 체크하는 정규식을 사용하려 했는데 JavaScript나 Java의 경우 구글에 무수하게 많은데


C# 정규식의 경우 구글링을 해도 잘 나오지 않아서 직접 만들어야 했습니다.


다른 분들의 경우 제가 만든게 활용할만 하시면 사용하시라고 포스팅합니다.


제가 만든 정규식은 아래와 같습니다.


하이픈 없이 입력 시
@"01{1}[016789]{1}[0-9]{7,8}"

하이픈 포함하여 입력 시
@"01{1}[016789]{1}-[0-9]{3,4}-[0-9]{4}"


하이픈 없이 입력 시에는


10자리나 11자리 (0111231234 혹은 01012341234 등)에 따라


처음 01이 들어오며 세 번째 자리에는 010, 011, 016, 017, 018, 109만 허용할 수 있게 0, 1, 6, 7, 8, 9만 입력할 수 있도록 했습니다.


그리고 뒤에 올 수 있는 7자리 혹은 8자리는 0~9의 숫자만 입력할 수 있도록 체크하였습니다.



하이픈 포함하여 입력 시에는


12자리나 13자리 (011-123-1234 혹은 010-1234-1234 등)에 따라


처음 01이 들어오며 세 번째 자리는 위와 동일하게 하였고, 네 번째 자리에 하이픈(-)을 체크하며 그 다음 3자리나 4자리가 0~9의 숫자만 들어올 수 있고


마지막 4자리가 0~9의 숫자만 들어올 수 있게 체크하였습니다.



그래서 활용방안 소스는 아래와 같이


phoneNumCheck()는 하이픈없이 입력 시에 활용 방안이고


phoneNumCheck2()는 하이픈까지 입력 시 활용 방안입니다.


using System.Text.RegularExpressions;

// 휴대전화번호 체크 (하이픈 없을 시)
private void phoneNumCheck()
{
    string phone = "01012341234";
    if (phone.Length == 10 || phone.Length == 11)
    {
        Regex regex = new Regex(@"01{1}[016789]{1}[0-9]{7,8}");

        Match m = regex.Match(phone);
        if (m.Success)
        {
            MessageBox.Show("@@ Success");
        }
        else
        {
            MessageBox.Show("@@ 휴대전화 번호 아님");
        }
    }
    else
    {
        MessageBox.Show("@@ 자릿수 맞지 않음");
    }

}

// 휴대전화번호 체크 (하이픈 포함)
private void phoneNumCheck2()
{
    string phone = "011-123-1234";
    if (phone.Length == 12 || phone.Length == 13)
    {
        Regex regex = new Regex(@"01{1}[016789]{1}-[0-9]{3,4}-[0-9]{4}");

        Match m = regex.Match(phone);
        if (m.Success)
        {
            MessageBox.Show("@@ Success");
        }
        else
        {
            MessageBox.Show("@@ 휴대전화 번호 아님");
        }
    }
    else
    {
        MessageBox.Show("@@ 자릿수 맞지 않음");
    }

}


잘못된 부분이나 궁금하신 점 댓글주세요.


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


감사합니다.












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

,

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


C# / .NET 정규표현식이 구글링해서 나오는게 많이 없더군요..


그래서 혹시나 필요할지 몰라 메모합니다.


정규 표현식에 사용되는 특수 문자

'.'  => 점

임의의 한 문자를 의미합니다.

a.c -> abc, aec, avc, …

.us -> bus, cus, dus, …

'*'

바로 앞의 문자가 없거나 하나 이상인 경우

s*e -> e, se, see, ssse, …

abc* -> ab, abc, abcc, abccc, …

h*im -> im, him, hhim, hhhim, …

'+'

바로 앞의 문자가 하나 이상

s+e -> se, sse, ssse, …

'?'

바로 앞의 문자가 없거나 하나뿐인 경우

th?e -> e, the 두가지 표현이 유일함

'^'

바로 뒤의 문자열로 시작

^The.. 뒷부분부터 공백까지 검사. -> The girl is, Theather

^a?bc -> bc, abc, …

^.e -> he, me, request, settle, …

^s.e?.. E는 나와도되고 안나와도 됩니다. -> sa, sae, sb, sbe, …

'$'

바로 앞의 문자열로 종료

a?bc$ -> eeabe, seebc, bc..

+.e$ -> onthetoe, bctae, appetittle, …

s?c+$ -> e, se, ee, eee, seee, seee, …

'[ ]'

[ ] 안에 있는 문자 중 하나(범위의 경우 '-'로 지정합니다.)

[ab]cd -> acd, bcd, …

[a-z] -> 알파벳 소문자

[a-zA-Z] -> 알파벳

[0-9] -> 숫자

ag[a-z] -> aga, agbcd, agzzz, …

^ab[cd]ef -> abcef, abdef, …

^[a-zA-Z] -> 영문자로 시작

^[가-힣] 한글로 시작해야 할 때

[a^-zA-Z0-9] -> '^' 표시가 대괄호 안으로 들어갈 경우 제외의 의미가 됩니다. 부정의 의미. ->영문자나 숫자로 시작할 수 없습니다.

[a-zA-Z0-9]$ -> 영문자나 숫자로 종료

"[가-힣]" -> 한글 완성형만 가능합니다. "ㅋㅋ", "ㅎㅎ" 같은 구문은 불가능합니다.

"[abc]" -> abc중 하나라는 뜻 -> c#문법으로 if("a" || "b" || "c")와 같음.

'{ }'

{ } 앞의 문자나 문자열의 출현 횟수, Schema에서 min / maxoccur과 같은 개념

a{2}b -> aab, … -> a가 꼭 2회 나와야 함

a{2, }b -> aab, aaab, aaaab, … -> a가 2회 이상 나와야 함

a{2, 3}b -> aa, aaab -> a가 2회~3회 나와야 함

'( )'

( )안에 있는 문자를 그룹화

a(bc){2} -> abcbc -> a 다음 bc가 2회 나와야 함

a(bc)* -> abcbcbcbc -> a 다음 bc의 출현이 무한대로 가능 함

'|'

or 연산자

영어로만 아이디를 만들라 -> [a-zA-Z]+ 공백없는 영어단어

He|She -> he, she is..

(He|She)is -> Heis, Sheis

특수문자 사용

^ [] $ () | * + ? {} \

앞부분에 \를 붙여서 사용합니다.

\*+ -> *가 하나 이상 포함된 패턴.. -> *나 **나 ***이 무한대로 가능

\d : 정수

\d{2, 3} - / d{3,4} - / d{4} : 전화번호 찾는 정규식

\D : 숫자가 아닌 나머지 모두

\w : [a-zA-Z0-9]의 줄임 표현

\W : [^a-zA-Z0-9] 영문자와 숫자만 아니면 됨.

\s : 공백

\S : 공백이 아닌 나머지



감사합니다.


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

,

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


핸드폰 번호를 하이픈 없이 입력 받아 하이픈을 넣어서 사용하여야 할 때 하이픈 넣는 방법에 대해 알아보도록 하겠습니다.


많은 방법이 있지만 저는 제일 쉽게 접할 수 있는 Substring으로 쪼개서 "-"를 중간중간 더하는 방식으로 진행하였습니다.


0111234567과 같은 10자리 번호와 01012345678과 같은 11자리 번호에 대해서 처리하였습니다.


저는 정규식으로 전화번호가 맞는지 먼저 체크하고 이 코드를 타기 때문에 가볍게 10인지 아닌지만 구분했지만


if / else 문의 조건을 조금만 수정하면 더욱 더 완벽하게 처리하실 수 있으실거에요.


해당 소스는 아래와 같습니다.


public void phoneNumHyphen(){
    string phone = "0110000000";
    string str_phoneNumHyphen;

    string[] phoneNumSplit = new string[3];

    if (phone.Length == 10)
    {
        phoneNumSplit[0] = phone.Substring(0, 3);
        phoneNumSplit[1] = phone.Substring(3, 3);
        phoneNumSplit[2] = phone.Substring(6, 4);
    }
    else
    {
        phoneNumSplit[0] = phone.Substring(0, 3);
        phoneNumSplit[1] = phone.Substring(3, 4);
        phoneNumSplit[2] = phone.Substring(7, 4);
    }

    str_phoneNumHyphen = phoneNumSplit[0] + "-" + phoneNumSplit[1] + "-" + phoneNumSplit[2];

    MessageBox.Show("@@ PhoneNum : " + str_phoneNumHyphen);
}


위 소스로 빌드하면 아래와 같은 결과를 얻을 수 있습니다.




추가!!!!!!!!


더 간단한 방법이 있었습니다.


private void phoneNumHyphen()
{
    string phoneNum= "01012341234";
    string phoneNumHyphen;

    if (phoneNum.Length == 11)
    {
        phoneNumHyphen = phoneNum.Insert(3, "-");
        phoneNumHyphen = phoneNumHyphen.Insert(8, "-");
    }
    else
    {
        phoneNumHyphen = phoneNum.Insert(3, "-");
        phoneNumHyphen = phoneNumHyphen.Insert(7, "-");
    }
    MessageBox.Show("@@ PhoneNum : " + phoneNumHyphen);
}


잘못된 부분이나 궁금하신 점 댓글주세요.


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


감사합니다.



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

,