기존 Node.js 게시글에서는 단순히 html 페이지를 띄우는 서버페이지를 만들었고, 이번에는 데이터를 송신, 수신 할 수 있는 기능을 추가할 것이다.

 

1. 서버로 데이터 보내기

먼저 URLSession을 이용해 json Data를 서버로 보내는 예제를 진행해보았다.

 

 

간단하게 URLSession에 대해 살펴보면 다음과 같다.

  • URLSession이란 HTTP를 포함한 여러 통신을 하는 필요한 기능을 제공해주는 객체라고 볼 수 있다.

  • 이 URLSession을 이용한 것이 Alamofire , AFNetworking 라이브러리 등이 있다.

    (URLSession을 이용해 직접 통신을 구현해 본 다음 Alamofire 라이브러리를 이용해 간단하게 통신하는 방법을 배워볼 것이다.)

  • http 통신이 request와 response로 이루어진 것 처럼, URLRequest , URLResponse를 이용해 데이터 송수신이 가능하다.

 

버튼을 눌러 텍스트필드의 데이터를 서버에 보내는 예제를 간단하게 구현해보았다.

텍스트필드에 데이터를 입력하고 '데이터 전송' 버튼을 누르면 서버에 텍스트필드의 데이터가 전송되는 방법이다. 결과화면은 아래와 같다.

 


시작!

 

 

1. 서버에 보낼 데이터를 dictionay 형태로 저장한다.

  • 여기서는 텍스트 필드에 넣은 데이터에 임의의 key 값을 붙여 간단하게 만들었다.

let dic: Dictionary = ["message": message]	// 서버로 보낼 데이터

 

 

2. 데이터를 보낼 url을 설정하고, 이 url로 URLRequest 를 정의한다.

URLRequest 이란?
[프로토콜이나 URL Scheme에 독립적인 URL 로드 request 방식]

URLRequest는 두 개의 필수적인 url load 요소로 캡슐화 되어있다. 이는 로드되는 url과 이를 로드할 때 사용하는 정책이다. HTTP와 HTTPS 요청에 대해서 URLRequestsms HTTP 메서드(GET, POST 등)와 HTTP 헤더를 가지고 있다.URLRequest는 오직 요청에 대한 정보만을 나타낸다. 'URLSsession'과 같은 다른 클래스들을 사용하여 서버에 데이터를 보낸다. swift 코드를 사용할 때에는 'NSURLRequest'나 'NSMutableURLRequest' 클래스보다 이 구조를 선호하여 사용하라.

[출처 : Apple Developer Documentation]

 

  • 설명에 나와있는 것 처럼 URLRequest 는 요청을 보내는 것에 대한 정보만을 가지고 있으며, 실제로 이를 서버에 전송하는 것은 URLSession 이 담당한다.
guard let url = URL(string: "http://localhost:3000") else {
	return	// 데이터를 보낼 서버 url
}
                
var request = URLRequest(url: url)
request.httpMethod = "POST"	 	// http 메서드는 'POST'
        
do { // request body에 전송할 데이터 넣기
	request.httpBody = try JSONSerialization.data(withJSONObject: dic, options: .prettyPrinted)
} catch {
	print(error.localizedDescription)
}
        
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
  • URLRequest의 바디를 설정하는 부분에는 JSONSerializtion 객체를 이용하였는데, 이것은 Foundation에서 제공하는 데이터를 json 데이터로 변경해주는 역할을 한다.
  • 하단의 request.addValue 는 POST 방식으로 데이터를 보낼 때 추가해주는 것이다.
    (Content-Type 과 Accept-Type 은 서버와 데이터를 주고 받을 때 그 데이터의 형식에 대해 명시하는 것 같다.)

 

 

3. URLSession 을 이용해 데이터를 서버에 보낸다.

let session = URLSession.shared
session.dataTask(with: request, completionHandler: { (data, response, error) in
	print("전송완료")
}).resume()
  • URLSession에 대해 조금 자세히 살펴보면 다음과 같다.
URLSession 및 관련 클래스들은 특정된 URL에 데이터를 다운로드하거나 업로드하는 API를 제공한다. 당신의 앱은 또한 이 API를 이용해 백그라운드 다운로드 작업을 진행할 수 있다. 당신의 앱이 실행되고 있지 않거나 suspend 상태일 때도 말이다. 당신은 이와 관련된 URLSessionDelegate와 URLSEssionTaskDelegate를 이용해 redirection과 같은 이벤트를 받거나 작업이 끝났음을 알 수 있다.

당신의 앱은 하나나 그 이상의 URLSession 인스턴스를 생성하며 이것들 각각은 관련된 전송 데이터 작업들을 조정한다. 예를 들어, 당신이 웹브라우저를 만든다면 당신의 앱은 아마 각 탭이나 윈도우마다 하나의 세션을 만들것이다. 이 각각의 세션 안에서 당신의 앱은 일련의 작업들을 추가할 것이고, 이것들은 특정 URL에 대한 요청을 가리킨다.

[Type of URL SEssions]
URLSession은 하나의 싱글턴 객체를 사용하며, 그 종류는 세 가지가 있다.
1) default session
2) ephemeral session
3) background session

 

 

이대로 실행하면 아래와 같이 에러에 대한 설명이 나온다.

  • 읽어보면 ~~ Trnasport Security policy requires~~ 이렇게 나오는데, 이는 https을 표준으로 사용하는 Xcode에서 http 로 시작하는 페이지에 대해 허용해주지 않아서 발생하는 에러임을 알 수 있다.

  • 이를 해결하기 위해서는 info.plist에 다음 딕셔너리를 추가해주어야 한다.

위와 같이 설정해주면 데이터 전송을 확인할 수 있다!

 

 


2. 서버에서 Post 로 데이터 수신하기

위에서는 앱에서 서버로 데이터를 보냈고, 서버에도 데이터를 받을 수 있는 코드가 있어야지 제대로 전송되어있음을 확인할 수 있다. 이전과 마찬가지로 서버는 node.js로 구현하였고, 데이터 수신을 위한 최소한의 코드만 작성하였다.

 

var express  = require('express');  // express framework 사용
var hostname = '172.30.1.28';       // localhost
var port     = 3000;                // 포트 번호
var http     = require('http');     // node 내장 모듈 불러옴

var app = express();
var bodyParser = require('body-parser')     // post 사용을 위한 모듈
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());


console.log('Server running at http://'+hostname+':'+port);


// 들어오는 데이터 읽기
var server = app.listen(port, function () {
    console.log('읽음');
});


// post method connect
app.post('/', function (req, res) {
    console.log('post 메서드 받음 ')
    console.log(req.body)
});

 

  • node.js에서 express를 이용하는 POST 통신 방법은 GET 방식과 다르게 body-parser 라는 모듈을 추가로 사용해 주어야 한다.
  • app.listen(port, func(){ }) 은 해당 포트로 들어오는 데이터를 읽는 부분이다.

  • app.post() 와 같은 방법을 이용하면, req 파라미터에 http 통신으로 들어온 데이터가 저장되게 된다. Header / body 중 데이터는 body 에 들어가므로, 콘솔에 body를 출력하면 앱에서 보낸 json 데이터를 확인할 수 있다.

 

 

터미널에서 서버를 실행시키고, 앱에서 데이터를 보내면 보낸 데이터를 터미널 콘솔에서 확인할 수 있다!!

 

* 앞서 node.js 를 이용해 서버를 구축하였고, 이번에는 iOS의 WKWebView를 이용해 만들어진 간단한 서버와의 통신을 연습해보려한다. 

* 첫 번째는 웹서버의 함수명을 그대로 가져와 해당 함수를 호출하는 방법이고, 두번재는 iOS의 URLSession.shared.dataTask() 를 이용해 통신해 보았다.

 

 

[node js 설정은 앞선 포스팅 소스코드를 이용한다.]

 

 

1. Navtive 버튼을 클릭 시 웹뷰 배경색 변경하기

 

1) 서버페이지에 배경색 변경 메서드를 생성한다.

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>앱을 만들어 보았읍니다.</title>

    <style>
        body {background: gray;}
    </style>
</head>
<body>
    <h1> 테스트 페이지에 오신걸 환영합니다!</h1>
    </br></br></br>
    <input type="text" name="input_box">
    <input type="button" value="버튼" onclick="clickButton()">
    
    <script>
        function clickButton() {
            alert("버튼을 눌렀다");
            document.body.style.background = 'blue'
        }

        function changeBackgroundColor() {
            document.body.style.background = 'yellow'
        }
    </script>
</body> 

 

  • native에서 웹뷰 영역을 확인하기 위해 배경색을 바꿔줬고,

  • 동작하는지를 확인하기 위해 버튼을 누르면 얼럿창이 뜨도록 해주었다.

  • changeBackgroundColor() 함수가 실행되면 배경색이 노란색으로 바뀐다.

 

2) Native 소스

  • 웹페이지 배경색을 변경하기 위한 버튼이 필요하므로, WKWebView의 사이즈를 조정하고 가운데에 둔다.

  • UKWebView를 설정해주고, 다음과 같은 소스코드만 입력하면 된다

override func viewDidLoad() {
	super.viewDidLoad()

	let serverURL = URL(string: "http://localhost:3000")	
  	let request = URLRequest(url: serverURL!)
	webView.load(request)
}

// 버튼 클릭 시 호출
@IBAction func clickRequestBtn(_ sender: Any) {
	webView.evaluateJavaScript("changeBackgroundColor()", completionHandler: nil)
}    

 

  • 먼저 정해진 url에 request를 날릴 URLRequest 를 생성한다.
  • 그리고 @IBOutlet 으로 가져온 webview에 이 request를 담아 load 메서드를 실행한다.

  • 서버 js파일의 changeBackgroundColor() 함수를 호출하는 메서드

 

결과 화면은 아래와 같다. 하단 버튼을 클릭하면 오른쪽과 같이 배경색상이 바뀐다.

 

** Apple 공식 문서를 참고하였습니다.

 

 

WKWebView란?

in-app 과 같이 웹 컨텐츠와의 상호작용을 보여주는 객체

  • 당신의 앱에 웹 컨텐츠를 추가하기 위해 UKWebView를 사용할 수 있다.
  • WKWebView 객체를 만들기 위해서는 웹 컨텐츠 로드를 위한 'request'를 보내야 한다.
  • WkWebView 내에'httpBody'컨텐츠를 넣어 'POST' request를 할 수 있다.
  • WKWebView는 iOS 8.0부터 사용할 수 있다.
    기존에는 UIWebView를 사용했으나, 성능상의 이유로 deprecate되고 현재는 WKWebView 사용을 권장하고 있다.

- init(frame:configuration:) // 객체 초기화
- loadHTMLString(_:baseURL:) // 로컬 html 파일 로딩을 시작하는 메서드
- load(_:)  // 웹 컨텐츠를 로드해 사용하는 메서드

- goBack()		// 웹 히스토리를 이용한 뒤로가기	
- goForward() 	// 웹 히스토리를 이용한 앞으로가기
- canGoBack()
- canGoForwatd()

- setMagnification(_:centeredAt:) // 코드로 웹컨텐츠 크기 조절하는 방법

 

WKWebView 사용 가이드

import UIKit
import WebKit
class ViewController: UIViewController, WKUIDelegate {
    
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myURL = URL(string:"https://www.apple.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }}

 

  • WKWebViewConfiguation

    • 웹뷰를 초기화하는 복사본 형태 (웹뷰 초기화에 필요)

  • URLRequest

    • 프로토콜이나 URL Scheme과 독립적인 URL load Request

    • URLRequest는 'load request'의 필수적인 속성 두 가지를 암호화한다.

      (URL 과 URL 로드에 사용되는 policy들 // URLRequest는 POST, GET과 같은 HTTP method와 HTTP 헤더를 가지고 있다.)

    • URLSession 과 같은 다른 클래스를 사용하여 서버에게 요청을 보낸다.

 

* 저번 포스팅에서 node.js 로 웹서버를 구축한 뒤 다음과 같이 간단하게 'Hello World'가 띄워지는 웹페이지를 확인해보았다.

이번에는 html 파일을 이용해 웹페이지를 만들어볼 것이다.

 

 

1.  Express 설치

  • Express.js는 Node.js 를 편리하게 사용할 수 있는 웹 프레임워크를 뜻한다. 웹개발을 위한 다양한 기능을 제공한다고 한다.

  • Express를 설치하기 전에 'npm'이 미리 설치되어 있어야 한다.

    • npm 설치 : npm install -g express-generator

    • express 설치 : npm install express

2. 웹페이지에서 띄워줄 html 파일 작성하기

<!DOCTYPE html>
 
<head>
    <meta charset="UTF-8">
    <title>웹페이지 타이틀</title>
</head>
 <body>
    <p>Hello world!!!!!!!!!!!</p>
    <p>Hi!</p>
</body> 

 

3. 터미널로 실행시킬 js 파일 작성하기

var express = require('express');   // express framework 사용
var fs = require('fs');     // 파일 로드시 사용
var http = require('http'); // node 내장 모듈 불러옴

var app = express();
var hostname = '172.30.120.240'; // localhost
var port = 3000;


console.log('Server running at http://'+hostname+':'+port);
 
app.get('/', function (req, res) {
    fs.readFile('index.html', function(error, data){
        if(error){
            console.log('에러가 발생했습니다.');
        }else{
            console.log('웹페이지 실행!');
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end(data);
        }
    })
});

 
var server = app.listen(3000, function () {
  console.log('앱 로드 성공입니까 11');
});

 

4. 웹서버 실행하기

  • 터미널에 위 js 파일이 있는 경로로 들어가 'node 파일이름.jsp' 를 입력해 웹서버를 실행시킨다.
  • 아래와 같이 호스트 ip를 웹브라우저에 입력하면 제대로 띄워지는 것을 확인할 수 있다.

 

** 이제 옛날에 했던 html , css, javaScript 이용해서 페이지를 보기좋게 만들어주면 된다... 갈 길이 멀다...

*아이폰에서 webView 컨트롤 예제를 진행하기 위해 node.js 를 이용해 간단한 웹서버를 구축해보려 한다.

 서버에 대한 지식이 거의 0에 가깝지만 조금이라도 배울 수 있는 기회라 생각하고 프로젝트를 진행해 볼 것이다.

 

 

 

1. node.js 설치하기

  • 설치방법은 간단하다. (맥을 이용하고 있으므로, 맥 기준으로 정리하였다.)
    node.js 다운로드 사이트(https://nodejs.org/ko/download/)에서 설치하면 끝이다.

2. javaScript 로 웹서버를 구축하는 소스를 작성한다.

  • 컴파일러는 Visual Code를 이용하였다.

var http = require('http'); // node 내장 모듈 불러옴
var hostname = '172.30.120.240'; // localhost와 동일
var port = 3000;

http.createServer(function(req, res){
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.end('Hello World\n');
}).listen(port, hostname);

console.log('Server running at http://'+hostname+':'+port);
  • 이 짧은 코드를 입력하면 웹서버 구축이 끝난다. (hostname 에는 본인의 ip를 입력해주면 된다.)
    (참고 : https://sanghaklee.tistory.com/)

 

3. 웹서버 구축 확인하기

  • 터미널에 위 js 파일이 저장된 폴더로 들어가 node test.js 명령어를 입력해준다.

           ((다음과 같은 값이 출력되면 서버가 잘 구축된 것이다.))

  • 웹브라우저에 본인 ip를 입력해 실행되는지 확인힌다.

 

* native 웹 통신 방법을 찾아보니 기본부터 이해해야 할 필요가 있어서 통신방법과 특징에 대해 간단하게 정리해보았다.

 

 

1.  HTTP 통신

클라이언트의 요청(request)이 있을 때만 서버가 응답(response)하고 곧바로 연결을 종료하는 단방향 통신 방식
  • sever에서 client 로 요청을 보낼 수 없음

  • HTTP 통신방법에는 GET 방식과 POST 방식 두 가지가 있다.

  • Socket 통신

    서버와 클라이언트가 특정 '포트'를 통해 실시간으로 양방향 통신을 하는 방식
    • 계속해서 연결을 유지하는 연결지향적 통신

    • 실시간 통신이 필요한 경우에 사용됨 (실시간 스트리밍 중계, 실시간 채팅 등)

GET 방식

  • 요청 데이터를 url에 담아서 보내는 방식.

  • 길이에 제한이 있고, 쿼리가 그대로 노출된다는 단점이 있다.

POST 방식

 

  • 요청 데이터를 HTTP 메세지의 body에 담아 보내는 방식

  • 길이 제한이 없고, 요청 데이터가 노출되진 않지만 추가적으로 보안에 신경써줘야 한다.

 

 

 

 

2. Socket 통신

서버와 클라이언트가 특정 '포트'를 통해 실시간으로 양방향 통신을 하는 방식
    • 계속해서 연결을 유지하는 연결지향적 통신

    • 실시간 통신이 필요한 경우에 사용됨 (실시간 스트리밍 중계, 실시간 채팅 등)

이번에는 다른 앱을 호출하고, 파라미터를 넘겨주는 방법을 함께 알아볼 것이다.

간단하게 사용자의 id와 pw를 입력받고, 이 중 id를 다른 앱에 넘겨주는 예제를 진행해보려한다.

 

1. 다른 앱 호출 할 준비하기 (AppA)

  • AppA의 info.plist에 아래 항목을 추가해주어야 'AppB'라는 앱을 호출할 수 있는 권한을 얻는다.

LSApplicationQueriesSchemes의 하위항목을 추가하는 방법을 몰라서 헤맸었는데, 오른쪽 타입을 'Array' 로 해주면 하위 항목을 입력할 수 있다.

 

  • Info.plist에 이를 추가해주지 않으면 아래와 같은 에러가 발생한다.

 

 

2. 다른 앱에서 호출받을 준비 하기 (AppB)

  • AppB의 URL Type에 본인의 앱 스킴이 무엇인지 정의해야, 다른 앱에서 해당 스킴으로 호출할 수 있다.

  • 아래와 같이 Project > Info > URL Types 에 번들id 와 url Schemes를 정해준다.

 

3. 다른 앱 호출하기 (AppA)

  • AppB:// 와 같이 다른 앱에서 정의해 놓은 url Schemes로 url을 생성한다.

    이 때 파라미터를 넣고 싶은 경우에는 AppB://id=hello 와 같은 타입으로 url을 정의한다.

  • 그 다음 canOpenUrl 을 이용해 해당 앱을 실행시킬 수 있는지 확인하고,

    가능할 경우 open(url: , options: , completionHandler: ) 메서드를 이용해 앱을 호출한다.

    ( 기존에는 openURL(string: ) 메서드가 존재했으나, deprecate되었다. )

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
	/*처리하는 부분은 내일해야지!!*/
}
@IBAction func login(_ sender: Any) {
	var id = userID.text ?? ""      
	let urlString = "AppB://" + "id=" + id
        
	if let appUrl = URL(string: urlString){
		if(UIApplication.shared.canOpenURL(appUrl)){
			UIApplication.shared.open(appUrl, options: [:], completionHandler: nil)
		}else{
			let showAlert = UIAlertController(title: "안내", message: "앱이 설치되어있지 않습니다.", preferredStyle: UIAlertController.Style.alert)
		}
	}
}

 

 

4. 호출될 때 넘겨받은 파라미터 처리하기 (AppB)

  • Url scheme을 이용해 앱이 호출되면 AppDelegate의 application(_:open:options:) 메서드가 호출된다. 파라미터를 처리해주기 위해 해당 메서드를 재정의한다.

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
	/*처리하는 부분은 내일해야지!!*/
}

 

 

 

 

# 공부를 위해 정리하는 글이므로, 정확하지 않을 수 있습니다. 

 

 

> 객체간 통신하는 방법에는 세 가지가 있다.

1. Notification
2. Delegate
3. Callback

 이 중, Notification 을 이용해 통신하는 방법에 대해 먼저 알아볼 것이다.

 

 

> Notification은 다른 뷰를 보고있음에도 띄워지지 않은 뷰의 메서드를 사용해 어떠한 이벤트를 처리하는 방법을 말한다. 예를 들어, 뷰A 버튼을 클릭했을 때 뷰B의 라벨 텍스트를 변경하는 것 등이 있을 것이다.

방법을 간단하게 살펴보면,

  1. addObserver를 이용해 NotificationCenter에 Notification 을 등록하고,

  2. post 를 이용해 노티를 발송해 연결된 함수를 실행한다.

 


[예제] NotiViewController에서 버튼 클릭 시, ViewController의 배경색을 변경한다.

 

- ViewController에서 노티피케이션을 등록한다.

NotificationCenter.default.addObserver(self,
                                       selector: #selector(changeBackground),
                                       name: NSNotification.Name(rawValue: "FirstNotification"),
                                       object: nil)

 

  • #selecter 에는 노티피케이션 수신 시 실행될 메서드를 넣어준다.

  • name에는 해당 노티피케이션의 고유 이름을 정해준다.

  • 여기서는 배경색을 바꿔주는 changeBackgroundColor 메서드를 호출했다.

    근데, #selector(changeBackground) 부분에서 'Argument of '#selector' refers to instance method 'changeBackground()' that is not exposed to Objective-C' 라는 오류메시지가 났다.

    func changeBackground()@objc changeBackground 로 변경해줘서 오류메시지가 사라졌는데, 왜 그런지 이유를 모르겠다..

 

- NotiViewController 에서 노티피케이션을 보낸다

NotificationCenter.default.post(name: Notification.Name(rawValue: "FirstNotification"), object: message)
  • name: 부분에 addObserver 메서드에서 정해놓은 고유이름을 넣어준다.

 

 

> 결과화면은 다음과 같다.

# 공부를 위해 정리하는 글이므로, 정확하지 않을 수 있습니다. 

 

 

* AppA에서 AppB 실행시키기 *

 

 

1. AppB의 URL Type 정의

 

  • 웹이든, 앱이든 url을 이용해 어떤 앱을 실행시키기 위해서는 그 앱 ID가 정의되어 있어야 한다.

    그렇기 때문에 호출될 AppB에 이 작업을 해둬야 한다.

  • Project > Info > URL Types 에 번들id 와 앱을 호출할 때 사용할 url Schemes를 정해준다.

     

2. AppA에 open 메서드 호출

  • 버튼 클릭 시 호출되는 메서드에서 다른 앱을 호출하는 메서드를 호출한다.

UIApplication.shared.open(URL(string: "AppB://")!, options: [:], completionHandler: nil)

 

 

 


open 함수에 웹url 을 입력하면 웹페이지도 호출할 수 있다.

UIApplication.shared.open(URL(string: "http://www.naver.com")!, options: [:], completionHandler: nil)

 

 

앱 설치여부나 실행가능여부 등을 확인하지 않고, 아주 간단하게 코드 한 줄로 다른 앱을 호출하는 방법에 대해 알아보았다.

다음에는 openURL 함수를 이용하는 방법, 데이터를 넘기는 방법에 대해 알아보려 한다.

// delay 1 - performSelector
[self performSelector:@selectors(changeName:) withObject:nil afterDelay:5.0];

// delay 2 - dispatch_after
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
   lblName.text = @"dispatch_after 편하네";
});

 

+ Recent posts