화면 캡처막기



액티비티에 다음 소스를 추가합니다

1
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
cs


Mac 홈디렉토리명 변경하기

 

 

다른 관리자 계정으로 접속해서 기존 계정의 홈디렉토리명을 변경합니다.

* 애플 가이드https://support.apple.com/ko-kr/HT201548

 

 

시스템 환경 설정 > 사용자 및 그룹

자물쇠를 클릭하여 새로만든 관리자 계정을 입력합니다

* 권한을 부여하고자 하는 기존의 계정에 마우스 오른쪽 클릭을 하고 고급옵션을 클릭합니다

 

 

* 홈 디레톡리 > 선택을 클릭합니다

 

 

* 사용자 폴더에서 기존 계정의 홈 디렉토리 명을 변경합니다

* 열기를 클릭합니다

 

 

* 홈 디렉토리 필드의 변경된 홈 디렉토리 명과 계정 이름 필드를 똑같이 합니다

* 승인을 클릭합니다

Mac 관리자 권한 복구하기



관리자 계정을 새로 만들고 이 계정을 이용하여 관리자 권한이 없어진 기존의 계정에 관리자 권한을 부여합니다

* 저의 MAC 버전은 Sierra 10.13.3 입니다


1. 싱글 유저 모드로 부팅 : 맥을 재기동 하면서 부팅될 때 command(⌘) + s 를 누릅니다

 

 

2. 부팅화면에서 다음명령어를 입력합니다

    재기동후 바로 부팅화면으로 이동하지 않으면 기존 사용자 계정으로 로그인해서 이동 합니다

/sbin/mount -uw /

rm /var/db/.AppleSetupDone

* reboot

 

 

3. 재부팅되면 새로운 계정을 만드는 화면이 나타납니다

    새로운 관리자 계정을 만듭니다



4. 새로운 관리자 계정으로 접속해서 기존 계정에 관리자 권한을 부여합니다

시스템 환경 설정 > 사용자 및 그룹

* 자물쇠를 클릭하여 새로만든 관리자 계정을 입력합니다

* 권한을 부여하고자 하는 기존의 계정에 마우스 오른쪽 클릭을 하고 고급옵션을 클릭합니다

 

 

* 그룹필드에 admin 를 입력하여 기존의 계정에 관리자 권한을 부여합니다

ProgressBar 이용하여 로딩바 애니메이션 구현하기



프로그레스바에 애니메이션을 입혀 로딩바를 구현합니다.

* 프레임 애니메이션 방식으로 구현 합니다.

* 프레임 애니메이션 : 만화처럼 이미지를 여러개 만든후 돌리는 방식


1. drawable 폴더에 anim_intro.xml 파일을 만듭니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
 
    <item android:drawable="@drawable/anim_intro1" android:duration="100" />
    <item android:drawable="@drawable/anim_intro2" android:duration="100" />
    <item android:drawable="@drawable/anim_intro3" android:duration="100" />
    <item android:drawable="@drawable/anim_intro4" android:duration="100" />
    <item android:drawable="@drawable/anim_intro5" android:duration="100" />
 
    <item android:drawable="@drawable/anim_intro6" android:duration="100" />
    <item android:drawable="@drawable/anim_intro7" android:duration="100" />
    <item android:drawable="@drawable/anim_intro8" android:duration="100" />
    <item android:drawable="@drawable/anim_intro9" android:duration="100" />
    <item android:drawable="@drawable/anim_intro10" android:duration="100" />
 
    <item android:drawable="@drawable/anim_intro11" android:duration="100" />
    <item android:drawable="@drawable/anim_intro12" android:duration="100" />
    <item android:drawable="@drawable/anim_intro13" android:duration="100" />
    <item android:drawable="@drawable/anim_intro14" android:duration="100" />
    <item android:drawable="@drawable/anim_intro15" android:duration="100" />
 
    <item android:drawable="@drawable/anim_intro16" android:duration="100" />
    <item android:drawable="@drawable/anim_intro17" android:duration="100" />
 
</animation-list>
cs


* 이미지를 한장씩 넘기며 애니메이션을 구현할 것이므로 여러장의 이미지를 준비합니다

* duration : 애니메이션이 넘어가는 속도, 단위는 ms

 

 

2. progressbar 에 적용

1
2
3
4
5
6
7
8
9
<ProgressBar
        android:layout_marginLeft="48dp"
        android:layout_marginRight="48dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:indeterminateDrawable="@drawable/anim_intro"
        android:layout_width="0dp"
        android:layout_height="6dp" />
cs


indeterminateDrawable 속성에 drawable 폴더에 생성한 애니메이션을 적용합니다



NDK JNI이용하여 C/C++ 라이브러리 호출하기

- gradle 설정 : http://ghj1001020.tistory.com/761  참고

- calculator 라는 C파일(라이브러리)을 만들어서 JNI를 통한 호출



MainActivity.java : Jni 로드및 호출

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.ghj.jnitwo;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    TextView txtResult;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        int add = getCalculator(123'+');
        int minus = getCalculator(123'-');
        int multiply = getCalculator(123'*');
        int divide = getCalculator(123'/');
 
        txtResult.append("덧셈 : "+add+"\n");
        txtResult.append("뺄셈 : "+minus+"\n");
        txtResult.append("곱셈 : "+multiply+"\n");
        txtResult.append("나눗셈 : "+divide+"\n");
    }
 
 
    static {
        //JNI 로드
        System.loadLibrary("jni-calculator");
    }
 
    public native int getCalculator(int a, int b, char type);
}
 
cs


jni-calculator.c : Jni 파일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <jni.h>
#include "calculator.h"
 
 
/**
 * @desc : JNI 를 이용하여 c/c++ 로 된 라이브러리를 호출할 수 있다
 */
JNIEXPORT jint JNICALL
Java_com_ghj_jnitwo_MainActivity_getCalculator(JNIEnv *env, jobject instance, jint a, jint b, jchar type) {
 
    if(type == '+'){
        add(a, b);
    }else if(type == '-'){
        minus(a, b);
    }else if(type == '*'){
        multiply(a, b);
    }else if(type == '/'){
        divide(a, b);
    }
}
cs


calculator.h : 임의의 라이브러리 헤더파일

1
2
3
4
5
6
7
8
9
10
#ifndef JNITWO_CALCULATOR_H
#define JNITWO_CALCULATOR_H
 
extern int add(int a, int b);
extern int minus(int a, int b);
extern int multiply(int a, int b);
extern int divide(int a, int b);
 
#endif //JNITWO_CALCULATOR_H
 
cs


calculator.c : 임의의 라이브러리 소스파일

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "calculator.h"
 
//덧셈
int add(int a, int b){
    return a + b;
}
 
//뺄셈
int minus(int a, int b){
    return a - b;
}
 
//곱셈
int multiply(int a, int b){
    return a * b;
}
 
//나눗셈
int divide(int a, int b){
    return a / b;
}
cs


main_activity.xml : 화면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.ghj.jnitwo.MainActivity">
 
    <TextView
        android:id="@+id/txtResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
 
cs


build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'
 
model {
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.3"
        defaultConfig {
            applicationId "com.ghj.jnitwo"
            minSdkVersion.apiLevel 19
            targetSdkVersion.apiLevel 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
//                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                proguardFiles.add(file('proguard-android.txt'))
            }
        }
 
        ndk {
            moduleName 'jni-calculator'
 
        }
    }
}
...
cs



결과

c라이브러리를 이용하여 사칙연산을 실행


HTTP 통신하기2

- IOS 보안 정책으로 HTTP 통신을 하기 위한 설정 진행 : http://ghj1001020.tistory.com/762


ViewController.swift)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import UIKit
 
class ViewController: UIViewController {
    
    @IBOutlet weak var txtResponse: UITextView!
    
    let strUrl : String = "http://swopenAPI.seoul.go.kr/api/subway/sample/"
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
 
 
    @IBAction func onHttpRequest(_ sender: Any) {
        let api = strUrl + "/json/realtimePosition/1/5/1호선"
        //URL에 한글이 있기 때문에 인코딩 해준다
        let encoding = api.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        //URL생성
        let url = URL(string: encoding!)
        
        if let _url = url {
            var request = URLRequest(url: _url)
            request.httpMethod = "get" //get : Get 방식, post : Post 방식
            
            //header 설정
//            request.setValue("", forHTTPHeaderField: "")
            //post body 설정
//            var requestBody : String = ""
//            request.httpBody = requestBody.data(using: .utf8)
            
            let session = URLSession.shared
            let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) in
                //error 일경우 종료
                guard error == nil && data != nil else {
                    if let err = error {
                        print(err.localizedDescription)
                    }
                    return
                }
                
                //data 가져오기
                if let _data = data {
                    if let strData = NSString(data: _data, encoding: String.Encoding.utf8.rawValue) {
                        let str = String(strData)
                        print(str)
                        //메인쓰레드에서 출력하기 위해
                        DispatchQueue.main.async {
                            self.txtResponse.text = str
                        }
                    }
                }else{
                    print("data nil")
                }
            })
            task.resume()
        }
    }
}
 
 
cs


결과

- 버튼 클릭시 지하철 운행


HTTP 통신하기1 - 특정 도메인과 HTTP 통신 허용하기


1. 특정 도메인과 HTTP 통신 허용하는 방법

Info.plist -> Add Row 

-> App Transport Security Settings선택 (NSAppTransportSecurity 입력) -> Add Row

-> Exception Domains선택 (NSExceptionDomains 입력) -> Add Row

-> 도메인 입력 -> Add Row

-> Key : NSTemporaryExceptionAllowsInsecureHTTPLoads 입력 , Type : Boolean , Value : True


2. 전체의 HTTP 통신을 허용하는 방법

Info.plist -> Add Row 

-> App Transport Security Settings선택 (NSAppTransportSecurity 입력) -> Add Row

-> Allow Arbitrary Loads선택 (NSAllowsArbitraryLoads 입력) , Value : True

NDK HelloWorld

- 사이트 : https://codelabs.developers.google.com/codelabs/android-studio-jni/index.html?#0


1) gradle wrapper 사용

Preferences (Settings) -> Build, Execution, Deployment -> Build Tools -> Gradle -> Use Default Gradle wrapper (recommended) 


2) NDK 다운로드

Tools -> Android -> SDK Manager -> SDK Tools -> NDK (Android NDK) 선택 -> Apply


3) gradle 설정

3-1) build.gradle (Project:)

- classpath 'com.android.tools.build:gradle-experimental:0.9.3' 로 교체

   (http://jcenter.bintray.com/com/android/tools/build/gradle-experimental 에서 최신버전 확인)

1
2
3
4
5
6
7
8
9
10
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
//        classpath 'com.android.tools.build:gradle:2.3.2'
 
        classpath 'com.android.tools.build:gradle-experimental:0.9.3'
    }
}
cs


3-2) gradle-wrapper.properties

- distributionUrl 최신버전으로 설정

1
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
cs


3-3) build.gradle (Module:)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'
 
model {
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.3"
 
        defaultConfig {
            applicationId "com.ghj.ndkhelloworld"
            minSdkVersion.apiLevel 19
            targetSdkVersion.apiLevel 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
 
        buildTypes {
            release {
                minifyEnabled false
//                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                proguardFiles.add(file('proguard-android.txt'))
            }
        }
    }
}
...
cs


4) 소스코딩

4-1) build.gradle 에 ndk moduleName 추가 -> Syn Now 클릭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'
 
model {
    android {
        compileSdkVersion 25
        buildToolsVersion "25.0.3"
 
        defaultConfig {
            applicationId "com.ghj.ndkhelloworld"
            minSdkVersion.apiLevel 19
            targetSdkVersion.apiLevel 25
            versionCode 1
            versionName "1.0"
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
 
        buildTypes {
            release {
                minifyEnabled false
//                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
                proguardFiles.add(file('proguard-android.txt'))
            }
        }
 
        ndk {
            moduleName "hello-world"
        }
    }
}
cs


4-2) MainActivity.java
- System.loadLibrary의 라이브러리 이름과 build.gradle의 moduleName 이 같아야 한다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.ghj.ndkhelloworld;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    static {
        System.loadLibrary("hello-world");
    }
 
    public native String getHelloWorld();
}
 
cs


4-3) jni 파일 생성

- getHelloWorld를 길게 누른후 전구를 눌러 팝업메뉴에서 jni 파일생성 클릭


4-4) hello-world.c

1
2
3
4
5
6
#include <jni.h>
 
JNIEXPORT jstring JNICALL
Java_com_ghj_ndkhelloworld_MainActivity_getHelloWorld(JNIEnv *env, jobject instance) {
    return (*env)->NewStringUTF(env, "Hello World! From NDK");
}
cs


4-5) activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ghj.ndkhelloworld.MainActivity">
 
    <TextView
        android:id="@+id/txtNDK"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
 
</LinearLayout>
 
cs


4-6) MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.ghj.ndkhelloworld;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
 
public class MainActivity extends AppCompatActivity {
 
    TextView txtNDK;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        txtNDK = (TextView)findViewById(R.id.txtNDK);
 
        //Hello World 출력
        txtNDK.setText(getHelloWorld());
    }
 
    static {
        System.loadLibrary("hello-world");
    }
 
    public native String getHelloWorld();
}
 
cs



결과


SQLite 사용하기2 - 테이블생성, 데이터 INSERT, UPDATE, SELECT 

- db.executeStatements()

- db.executeUpdate()

- db.executeQuery()



ViewController.swift)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import UIKit
 
class ViewController: UIViewController {
    //ui
    @IBOutlet weak var txtText: UITextView!
    @IBOutlet weak var btnInsert: UIButton!
    @IBOutlet weak var btnUpdate: UIButton!
    @IBOutlet weak var btnSelect: UIButton!
    
 
    var dbPath : String = ""
    let dbName : String = "test.db"
    
    let sqlCreate : String = "CREATE TABLE IF NOT EXISTS TEST ( "
                                + " ID    INTEGER PRIMARY KEY AUTOINCREMENT , "
                                + " NAME  TEXT , "
                                + " PHONE TEXT "
                            + ")"
    
    //데이터 입력
    let sqlInsert : String = "INSERT INTO TEST (NAME, PHONE) VALUES ('권혁준' , '010-1234-1234')"
    
    //데이터 보기
    let sqlSelect : String = "SELECT ID, NAME, PHONE FROM TEST ORDER BY ID"
    
    //데이터 수정
    let sqlUpdate : String = "UPDATE TEST SET NAME='홍길동', PHONE='010-1234-5678' WHERE ID=?"
    
 
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let dirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let docPath = dirPath[0]
        
        dbPath = docPath+"/"+dbName
        
        let fileManager = FileManager.default
        if !fileManager.fileExists(atPath: dbPath as String) {
            //DB 객체 생성
            let database : FMDatabase? = FMDatabase(path: dbPath as String)
         
            if let db = database {
                //DB 열기
                db.open()
                //TABLE 생성
                db.executeStatements(sqlCreate)
                //DB 닫기
                db.close()
                
                NSLog("TABLE 생성 성공")
            }else{
                NSLog("DB 객체 생성 실패")
            }
        }
    }
    
    @IBAction func onDBInsert(_ sender: Any) {
        //DB 객체 생성
        let database : FMDatabase? = FMDatabase(path: dbPath as String)
        
        if let db = database {
            //DB 열기
            db.open()
            //INSERT
            db.executeUpdate(sqlInsert, withArgumentsIn: [])
            
            if db.hadError() {
                txtText.text = "DB INSERT 실패 \(db.lastErrorMessage())"
            }else{
                txtText.text = "DB INSERT 성공"
                db.commit()
            }
            
            //DB 닫기
            db.close()
        }else{
            NSLog("DB 객체 생성 실패")
        }
    }
    
    @IBAction func onDBUpdate(_ sender: Any) {
        //DB 객체 생성
        let database : FMDatabase? = FMDatabase(path: dbPath as String)
        
        if let db = database {
            //DB 열기
            db.open()
            //UPDATE
            db.executeUpdate(sqlUpdate, withArgumentsIn: [1])
            
            if db.hadError() {
                txtText.text = "DB UPDATE 실패 \(db.lastErrorMessage())"
            }else{
                txtText.text = "DB UPDATE 성공"
                db.commit()
            }
            
            //DB 닫기
            db.close()
        }else{
            NSLog("DB 객체 생성 실패")
        }
    }
    
    @IBAction func onDBSelect(_ sender: Any) {
        //DB 객체 생성
        let database : FMDatabase? = FMDatabase(path: dbPath as String)
        
        if let db = database {
            //DB 열기
            db.open()
            //SELECT
            let result : FMResultSet? = db.executeQuery(sqlSelect, withArgumentsIn: [])
            if let rs = result {
                var select : String = ""
                while rs.next(){
                    select += "ID : "+rs.string(forColumn: "ID")! + ", NAME : " + rs.string(forColumn: "NAME")! + ", PHONE : " + rs.string(forColumn: "PHONE")! + "\n"
                }
                txtText.text = select
            }else{
                txtText.text = "데이터 없음"
            }
            
            //DB 닫기
            db.close()
        }else{
            NSLog("DB 객체 생성 실패")
        }
    }
    
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    
    }
}
 
 
cs



결과

데이터 저장

데이터 보기

데이터 수정


데이터 보기



SQLite 사용하기1 - 라이브러리 적용



1. 다운로드 : http://ccgus.github.io/fmdb/



2. src > fmdb 폴더의 파일을 복사 



3. Create Bridge Header 생성 : FMDB는 Objective-C로 만들어졌기 때문에 Swift와의 호환성을 위한 역할

SQLite-Bridging-Header.h) 

1
#import "FMDB.h"
cs

 


4. 프로젝트명 클릭 > Build Phases > Link Binary With Libraries



5. + 클릭 > libsqlite3.tbd Add 하여 라이브러리 추가

+ Recent posts