APN 푸시3 - 서버

 

1. 인증서 만들기 https://ghj1001020.tistory.com/797
2. iOS 클라이언트 https://ghj1001020.tistory.com/798
3. 서버 https://ghj1001020.tistory.com/799

 

 

pom.xml

JavaPNS 라이브러리 추가

1
2
3
4
5
6
7
        <!-- APNS -->  
        <dependency>
            <groupId>com.github.mlaccetti</groupId>
            <artifactId>javapns</artifactId>
            <version>2.3.2</version>
        </dependency>
 

 

 

ApnsServer.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
 
import javapns.notification.AppleNotificationServer;
import javapns.notification.AppleNotificationServerBasicImpl;
import javapns.notification.PushNotificationManager;
import javapns.notification.PushNotificationPayload;
import javapns.notification.PushedNotifications;
 
public class ApnsServer {
    
    private static final String CERT_FILE_PATH = "D:\\blog\\workspace\\web\\apns_ex.p12";    // 인증서 경로
    private static final String CERT_PASSWORD = "test1234";    // 인증서 만들때 입력한 패스워드
    private static final String DEVICE_TOKEN_ID = "1e1c9c3f4539288801101658251b3409222b20ff8b5507d7d9430985ebd96a74";    // iOS가 받은 푸시키
    
    public void sendApns() {
        PushNotificationManager pushManager = new PushNotificationManager();
        try {
            AppleNotificationServer pushServer = new AppleNotificationServerBasicImpl(CERT_FILE_PATH, CERT_PASSWORD, false);
            pushManager.initializeConnection(pushServer);
        
            List<Device> deviceList = new ArrayList<Device>();
            // device 추가
            Device device = new BasicDevice( DEVICE_TOKEN_ID );
            deviceList.add( device );
            
            PushNotificationPayload payload = PushNotificationPayload.complex();
            payload.addBadge(1);
            payload.addAlert("iOS 푸시 테스트 입니다.");
            payload.getPayload().put("message""메시지 내용을 입력해주세요.");
            
            PushedNotifications notis = pushManager.sendNotifications( payload, deviceList);
            
            int result = 0;
            if( notis != null && notis.getSuccessfulNotifications() != null ) {
                result = notis.getSuccessfulNotifications().size();
            }
        
            System.out.println"success size=" + result );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        ApnsServer server = new ApnsServer();
        server.sendApns();
    }
}
 

 

 

결과

APN 푸시2 - iOS 클라이언트

 

1. 인증서 만들기 https://ghj1001020.tistory.com/797
2. iOS 클라이언트 https://ghj1001020.tistory.com/798
3. 서버 https://ghj1001020.tistory.com/799

 

 

Signing & Capabilities > Capability 추가 버튼 클릭

- Background Modes : Remote notifications 추가

- Push Notifications 추가

 

AppDelegate.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
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // 푸시 권한 획득
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (isGrant, error) in
            guard isGrant else {
                return
            }
            
            DispatchQueue.main.async {
                application.registerForRemoteNotifications()
            }
        }
        
        return true
    }
    
    
    // 푸시 토큰 받기 성공
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let deviceTokenString = deviceToken.map String(format: "%02x", $0) }.joined()
        print(deviceTokenString)
    }
    
    // 푸시 토큰 받기 실패
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error.localizedDescription)
    }
 
 

 

APN 푸시1 - 인증서 만들기

 

1. 인증서 만들기 https://ghj1001020.tistory.com/797
2. iOS 클라이언트 https://ghj1001020.tistory.com/798
3. 서버 https://ghj1001020.tistory.com/799

 

 

푸시 인증서 발급하기

1. 애플 개발자 사이트 로그인 > Certificates, IDs & Profiles 클릭

 

2. Certificates, Identifiers & Profiles > Certificates 추가 버튼 클릭

 

3. Create Certificate

개발용 : Services > Apple Push Notification service SSL (Sandbox) 선택

배포용 : Services > Apple Push Notification service SSL (Sandbox & Production) 선택

Platform 과 푸시 기능을 추가할려는 앱의 App ID 선택

Certificate Sigining Request 파일 선택

인증서 파일 다운로드 후 인증서를 더블 클릭하여 실행

 

 

서버 인증서 만들기

키체인 접근 실행

위에서 설치한 인증서 파일과 키를 선택하여 마우스 오른쪽 버튼 > 2개 항목 내보내기 선택

파일명, 저장 위치 선택

암호 입력 (서버에서 푸시 보낼때 입력한 암호가 필요)

 

에러메시지

응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다.

 

 

해결

Signing & Capabilities > Capability 추가 버튼 클릭 > Push Notifications 을 추가한다

'IT > Ⅰ. IOS' 카테고리의 다른 글

iOS APN 푸시2 - iOS 클라이언트  (0) 2020.05.05
iOS APN 푸시1 - 인증서 만들기  (0) 2020.05.05
iOS message app 열기  (0) 2020.05.01
iOS PickerView 예제  (0) 2020.04.30
IOS (Swift) HTTP 통신하기2  (0) 2017.10.09

message app 열기

 

URL형태 : sms:전화번호&body=메시지

 

 

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
import UIKit
 
class ViewController: UIViewController {
    
    @IBOutlet var editMessage: UITextField!
 
    
    override func viewDidLoad() {
        super.viewDidLoad()
 
    }
 
    // 메시지앱으로 이동
    @IBAction func moveToMessageApp(_ sender: UIButton) {
        let message = editMessage.text
        var sms : String = "sms:01012341234"
 
        // 메시지 내용이 있으면 전화번호 뒤에 &body=메시지를 붙이고 인코딩을 한다
        if let msg = message , !msg.isEmpty {
            sms = sms + "&body=" + msg
        }
        sms = sms.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!   // 인코딩
 
        UIApplication.shared.open( URL.init(string: sms)!, options: [:], completionHandler: nil )
    }
}
 
 

 

 

결과

버튼 클릭시 메시지앱으로 이동하여 전화번호와 메시지를 설정한다

PickerView 예제

 

텍스트 필드 입력시 피커뷰 띄우기

피커뷰 위에 툴바를 추가하여 확인/취소 버튼 구현

 

 

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
import UIKit
 
class ViewController: UIViewController , UIPickerViewDelegate , UIPickerViewDataSource {
    
    @IBOutlet var editCity: UITextField!
    let pickerView = UIPickerView()
    var selectCity = "" // 피커뷰 선택시 값을 갖고 있다가 확인버튼 클릭시 텍스트필드에 세팅한다
    
    
    let pickerData = ["서울" , "경기도" , "인천" , "부산" , "대구" , "광주" , "대전" , "제주도"]  // 피커뷰에 보여줄 테스트 데이터
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        pickerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 220)
        pickerView.delegate = self
        pickerView.dataSource = self
        
        // 피커뷰 툴바추가
        let pickerToolbar : UIToolbar = UIToolbar()
        pickerToolbar.barStyle = .default
        pickerToolbar.isTranslucent = true  // 툴바가 반투명인지 여부 (true-반투명, false-투명)
        pickerToolbar.backgroundColor = .lightGray
        pickerToolbar.sizeToFit()   // 서브뷰만큼 툴바 크기를 맞춤
        // 피커뷰 툴바에 확인/취소 버튼추가
        let btnDone = UIBarButtonItem(title: "확인", style: .done, target: self, action: #selector(onPickDone))
        let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        let btnCancel = UIBarButtonItem(title: "취소", style: .done, target: self, action: #selector(onPickCancel))
        pickerToolbar.setItems([btnCancel , space , btnDone], animated: true)   // 버튼추가
        pickerToolbar.isUserInteractionEnabled = true   // 사용자 클릭 이벤트 전달
        
        editCity.inputView = pickerView // 피커뷰 추가
        editCity.inputAccessoryView = pickerToolbar // 피커뷰 툴바 추가
        
    }
    
    // 피커뷰 > 확인 클릭
    @objc func onPickDone() {
        editCity.text = selectCity
        editCity.resignFirstResponder()
        selectCity = ""
    }
    
    // 피커뷰 > 취소 클릭
    @objc func onPickCancel() {
        editCity.resignFirstResponder() // 피커뷰를 내림 (텍스트필드가 responder 상태를 읽음)
        selectCity = ""
    }
 
    
    // 피커뷰의 구성요소(컬럼) 수
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1    // 구성요소(컬럼)로 지역만 있으므로 1을 리턴
    }
    
    // 구성요소(컬럼)의 행수
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int-> Int {
        return pickerData.count
    }
 
    // 피커뷰에 보여줄 값 전달
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int-> String? {
        return pickerData[row]
    }
    
    // 피커뷰에서 선택시 호출
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        selectCity = pickerData[row]
    }
}
 
 

 

 

결과

텍스트 필드 클릭시 피커뷰가 나타나고 피커뷰에서 선택 후 확인 버튼 클릭시 텍스트 필드에 값이 세팅된다

 

 

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

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