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 하여 라이브러리 추가

타이머 사용하여 1초마다 1씩 증가하기

- Timer.scheduledTimer()

- Timer.invalidate()

- Timer.isValid



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
import UIKit
 
class ViewController: UIViewController {
 
    //ui
    @IBOutlet weak var btnStart: UIButton!
    @IBOutlet weak var btnEnd: UIButton!
    @IBOutlet weak var txtTime: UILabel!
    
    //timer
    var mTimer : Timer?
    var number : Int = 0
    
 
    override func viewDidLoad() {
        super.viewDidLoad()
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
 
    /** 타이머 시작버튼 클릭 */
    @IBAction func onTimerStart(_ sender: Any) {
        if let timer = mTimer {
            //timer 객체가 nil 이 아닌경우에는 invalid 상태에만 시작한다
            if !timer.isValid {
                /** 1초마다 timerCallback함수를 호출하는 타이머 */
                mTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerCallback), userInfo: nil, repeats: true)
            }
        }else{
            //timer 객체가 nil 인 경우에 객체를 생성하고 타이머를 시작한다
            /** 1초마다 timerCallback함수를 호출하는 타이머 */
            mTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerCallback), userInfo: nil, repeats: true)
        }
    }
 
    /** 타이머 종료버튼 클릭 */
    @IBAction func onTimerEnd(_ sender: Any) {
        if let timer = mTimer {
            if(timer.isValid){
                timer.invalidate()
            }
        }
        
        number = 0
        txtTime.text = String(number)
    }
    
    
    //타이머가 호출하는 콜백함수
    func timerCallback(){
        number += 1
        txtTime.text = String(number)
    }
}
cs



결과

타이머 시작 버튼을 클릭하면 숫자가 1씩 증가하며 타이머 종료 버튼을 클릭하면 타이머가 종료되고 숫자는 0이된다



SMS 수신하기 (브로드캐스트 사용)



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
30
31
32
33
34
35
36
37
38
39
40
41
package ghj.com.recvsms;
 
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
 
/**
 * Created by gwonhyeogjun on 2017. 6. 6..
 */
 
public class ReceiveSMS extends BroadcastReceiver {
 
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        SmsMessage[] msg;
        String receive = "";
 
        if(bundle!=null){
            //pdu 얻기
            Object[] pdus = (Object[])bundle.get("pdus");
            msg = new SmsMessage[pdus.length];
            for(int i=0; i<msg.length; i++){
                //PDU로부터 SmsMessage 객체로 변환
                if(Build.VERSION.SDK_INT>=23){
                    msg[i] = SmsMessage.createFromPdu((byte[])pdus[i], "3gpp");
                }else{
                    msg[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
                }
 
                //PDU로부터 전환번호 , 메시지를 반환
                receive += msg[i].getOriginatingAddress()+" : "+msg[i].getMessageBody().toString();
            }
            Toast.makeText(context, receive, Toast.LENGTH_SHORT).show();
        }
    }
}
cs



AndroidManifest.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <application>
        ...
        <receiver android:name=".ReceiveSMS">
            <intent-filter>
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
            </intent-filter>
        </receiver>
    </application>
 
 
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
 

cs



결과

Api로 SMS 보내기



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
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
package ghj.com.sendsms;
 
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.provider.Telephony;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
 
import java.util.ArrayList;
 
public class MainActivity extends AppCompatActivity {
 
    SmsManager mSMSManager;
    EditText editBody;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mSMSManager = SmsManager.getDefault();
        editBody = (EditText)findViewById(R.id.editBody);
 
        Button btnSend = (Button)findViewById(R.id.btnSend);
        btnSend.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendSms();
            }
        });
    }
 
 
    public void sendSms(){
        //메시지
        String body = editBody.getText().toString();
        //160자 이하의 메시지 리스트로 만든다
        ArrayList<String> bodyList = mSMSManager.divideMessage(body);
 
        //송신 인텐트
        PendingIntent sentPI = PendingIntent.getBroadcast(this0new Intent("SMS_SENT"), 0);
        //수신 인텐트
        PendingIntent recvPI = PendingIntent.getBroadcast(this0new Intent("SMS_DELIVERED"), 0);
 
        registerReceiver(mSentReceiver, new IntentFilter("SMS_SENT"));
        registerReceiver(mRecvReceiver, new IntentFilter("SMS_DELIVERED"));
 
        //여러개의 SMS 메시지를 전송
        if(bodyList.size() > 1){
            ArrayList<PendingIntent> sentPIList = new ArrayList<>();
            ArrayList<PendingIntent> recvPIList = new ArrayList<>();
            for(int i=0; i<bodyList.size(); i++){
                sentPIList.add(sentPI);
                recvPIList.add(recvPI);
            }
            mSMSManager.sendMultipartTextMessage("010-1234-5678"null, bodyList, sentPIList, recvPIList);
        }
        //1개의 SMS 메시지를 전송
        else{
            mSMSManager.sendTextMessage("010-1234-5678"null, body, sentPI, recvPI);
        }
    }
 
    BroadcastReceiver mSentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
             switch (getResultCode()){
                case RESULT_OK:
                    Toast.makeText(MainActivity.this"SMS Send", Toast.LENGTH_SHORT).show();
                    break;
                 case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                     Toast.makeText(MainActivity.this"ERROR_GENERIC_FAILURE", Toast.LENGTH_SHORT).show();
                     break;
                 case SmsManager.RESULT_ERROR_NO_SERVICE:
                     Toast.makeText(MainActivity.this"ERROR_NO_SERVICE", Toast.LENGTH_SHORT).show();
                     break;
                 case SmsManager.RESULT_ERROR_NULL_PDU:
                     Toast.makeText(MainActivity.this"ERROR_NULL_PDU", Toast.LENGTH_SHORT).show();
                     break;
                 case SmsManager.RESULT_ERROR_RADIO_OFF:
                     Toast.makeText(MainActivity.this"ERROR_RADIO_OFF", Toast.LENGTH_SHORT).show();
                     break;
            }
        }
    };
 
    BroadcastReceiver mRecvReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (getResultCode()){
                case RESULT_OK:
                    Toast.makeText(MainActivity.this"SMS Delivered", Toast.LENGTH_SHORT).show();
                    break;
                case RESULT_CANCELED:
                    Toast.makeText(MainActivity.this"SMS Delivered Fail", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
}
 
cs



xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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:orientation="vertical"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ghj.com.sendsms.MainActivity">
 
    <EditText
        android:id="@+id/editBody"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
 
    <Button
        android:id="@+id/btnSend"
        android:text="SMS 보내기"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
 
cs



AndroidManifest.xml

1
2
3
4
5
6
7
    <application>
       ...
    </application>
 
 
    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
cs



결과

+ Recent posts