종달랩 종다리 이야기

카카오톡, 페이스북, 구글 간편로그인 오류문제중 인증서부분

Computer Science/Android&iOS
반응형

디버그 모드에서는 대부분 SSO 로그인의 구현과 테스트가 쉽다.

 

하지만, 릴리즈로 바꾸는 과정에서는 새로이 인증키도 만들어야 되고, 이것으로 인증도 해야 하고, SSO 사이트에 들어가서 등록 및 키해쉬, SHA-1을 등록도 해야 한다.

 

이렇게 개발PC에서 등록한 것으로 완벽하게 테스트 마치고 앱스토어에 올렸는데, SSO오류가 나거나 앱이 그냥 뻗어버리는 경우가 발생할 수 있다.

 

카카오톡, 구글에서의 오류메시지를 실시간으로 출력해본 결과 인증이 잘못되었다고 나오는 것이다.

 

분명히 나는 제대로된 인증서로 제대로 키해쉬, SHA-1을 입력했는데...

 

만일 내가 구글플레이스토어에서 앱무결성관련 설정을 건드린적이 있다면, 이부분을 의심해야 한다.

 

구글에서는 내가 만든 앱이라도 이 인증서를 이용해서 다시 인증을 하는 작업을 하게 되는것이다. 

그로인해서 인증에 따른 MD5, SHA-1, SHA-256의 값이 변경이 되어버린채 등록이 된다.

 

그래서 내가 PC에 생성한 인증서관련 값들이 먹히지 않게 된다.

 

내가 설정한 앱에서 대충 여기까지 따라오시고, 앱서명탭을 누르면 오호라.. 구글이 비밀스럽게 사용하는 인증서 정보가 있다.

우리는 여기서 값들을 이용하기면 하면 된다.

 

만일 키해쉬를 추출해야 한다면, 

 

echo <SHA-1 인증서 지문> | xxd -r -p | openssl base64

이렇게 해서 해쉬값을 변환할 수 있다.

반응형

iOS 화면전환 및 데이터 전송방식(동기 방식)

Computer Science/Android&iOS
반응형

동기방식에서 데이터를 주고 받는 방식은 생각보다 직관적입니다.

 

Android나 일반적인 프로그램에서는 데이터를 함수를 통해서 전달하는 경우가 많습니다. 이동하려는 개체를 생성하고, 이곳에 전달할 데이터개체를 생성해서 초기값으로 넣어주고, 이동하려는 개체를 호출하는 그런 방식이 조금 일반적입니다.

 

하지만, iOS는 이부분에서 조금 더 직관적인 부분이 있습니다.

 

이제 아래 예를 통해서 해당 방식을 고민해봅시다.

 

왼쪽 ViewController는 오른쪽 ViewController에 값을 전달할거고, 오른쪽에 ViewController는 값을 전달받아서 표시하고, 수정할것입니다. 수정된 내용은 다시 왼쪽의 ViewController로 보내는 그런 순환방식입니다.

왼쪽에서 오른쪽으로 데이터를 보내고, 역시 오른쪽에서 왼쪽으로 보내는걸 상상합시다.

일단, 왼쪽에 VC를 보면 "입력되지 않았습니다."라고 표시된 3개의 값들이 있는데, 처음에는 아무런 값도 없다고 가정해봅시다.

 

먼저 중요하게 봐야 할 부분이 어느시점에 화면에 데이터값을 표시할것인가 입니다. 우선 코드를 먼저 봅시다.

 

class RegisterController: UIViewController {
  @IBOutlet var resultEmail: UILabel!
  @IBOutlet var resultUpdate: UILabel!
  @IBOutlet var resultInterval: UILabel!
  
  var paramEmail: String? = ""
  var paramUpdate: Bool? = true
  var paramInterval: Double? = 0
  
  override func viewWillAppear(_ animated: Bool){
    if let email = paramEmail{
      resultEmail.text = email
    }
    
    if let update = paramUpdate{
      resultUpdate.text = update == true ? "AutoUpdate":"No Auto"
    }
    
    if let interval = paramInterval{
      resultInterval.text = "\(Int(interval))"
    }
  }
  
  @IBAction func close(_ sender: Any){
    self.presentingViewController?.dismiss(animated: true)
  }
  
  @IBAction func showRegister(_ sender: Any){
    let uvc = self.storyboard!.instantiateViewController(withIdentifier: "FormVC")
    
    guard let vc = uvc as? FormController else {
      return
    }
    
    vc.paramEmail = self.paramEmail!
    vc.paramUpdate = self.paramUpdate!
    vc.paramInterval = self.paramInterval!
    
    uvc.modalTransitionStyle = UIModalTransitionStyle.coverVertical
    uvc.modalPresentationStyle = .fullScreen
    self.presnet(uvc, animated: true)
  }

코드를 보면 화면전환을 present형태로 하는 것을 확인할 수 있습니다. 만일 우리가 화면전환을 NavigationController로 한다면 마지막 코드를 다음과 같이 전환하면 됩니다.

 

 //self.present(rvc, animate: true)
 self.navigationController?.pushViewController(rvc, animated: true)

 

중요한 것은 3가지 입니다.

 

- 변수의 정의

- viewWillAppear()에서 화면갱신시 이전 ViewController로부터 전달받은 값으로 화면 갱신

- showRegister() 함수에서 이동할 개체를 확인한 후 해당 개체안에 정의된 변수에 직접 값을 입력

 

내용이 그렇게 어렵지 않으므로 설명은 생략하고, 나머지 ViewController의 코드를 살펴보겠습니다.

 

class FormController : UIViewController{
  @IBOutlet weak var email: UITextField!
  @IBOutlet weak var update: UILabel!
  @IBOutlet weak var interval: UILabel!
  
  @IBOutlet weak var isUpdate: UIswitch!
  @IBOutlet weak var ControlInterval: UIStepper!
  
  var paramEmail: String = ""
  var paramUpdate: Bool = false
  var paramInterval: Double = 0
  
  override func viewDidLoad(){
    self.email.text = paramEmail
    self.update.text = paramUpdate == true ? "Auto Update":"No Auto"
    self.isUpdate.setOn(paramUpdate, animated: true)
    self.interval.text = "\(Int(paramInterfal))"
  }
  
  @IBAction func onSwitch(_ sender: UISwitch){
    if sender.isOn == true{
      self.update.text = "Auto Update"
    } else {
      self.update.text = "No Auto"
    }
  }
  
  @IBAction func onStepper(_ sender: UIStepper){
    let value = Int(sender.value)
    self.interval.text = "\(value)"
  }
  
  @IBAction func onSubmit(_ sender: Any){
    let preVC = self.presentingViewController
    
    guard let vc = preVC as? RegisterController else {
      return
    }
    
    vc.paramEmail = self.email.text
    vc.paramUpdate = self.isUpdate.isOn
    vc.paramInterval = self.ControlInterval.value
    
    self.presentingViewController?.dismiss(animated: true)
  }
}

여기서도 주의깊게 볼 부분은 다음과 같습니다.

 

- 변수의 정의

- viewDidLoad()에서 외부로부터 전달받은 값으로 화면을 구성

- onSubmit() 함수에서 되돌아갈 ViewController를 그에 맞는 class로 형변환후 변수를 저장

 

여기서도 present에 대응하는 코드로 작성되었지만, NavigationController를 이용했다면 다음 함수만 변경해주면 됩니다.

 //self.presentingViewController?.dismiss(animated: true)
 self.navigationController?.popViewController(animated: true)

 

마지막으로 Segue를 통한 화면전환시의 데이터전달만 마지막으로 정리해봅시다.

 

모든 코드에서는 이동할 또는 돌아갈 ViewController를 미리 인지하고 그에 맞게 class를 변환해서 데이터를 넣어주었습니다. 그런데, Segue는 그런 과정이 없습니다. Segue를 통한 이동시에는 해당 Segue를 identifier를 통해서 호출하기만 했습니다. 그러면 데이터를 넣어주는 시점이 언제일까? 

 

- prepare()를 통해서 segue를 통한 이동/반환시에 해당 목적지를 구분해서 데이터를 넣어줍니다.

 

@IBAction func onPerformSegue(_ sender: Any){
  self.performSegue(withIdentifier: "ManualSubmit", sender:self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?){
  let dest = segue.destination
  guard let vc = dest as? ResultViewController else {
    return
  }
  
  rvc.paramEmail = self.email.text!
  rvc.paramUpdate = self.isUpdate.isOn
  rvc.paramInterval = self.interval.value
}

prepare함수를 오버라이드해서 그 시점에 이동할 ViewController를 확인하고 데이터를 넣어주면 됩니다. Action Segue일때도 해당 함수를 통해서 데이터를 넣어주면 됩니다.

 

 

반응형

iOS 화면전환 및 데이터 전송방식(비동기 방식)

Computer Science/Android&iOS
반응형

화면전환시 데이터를 주고받는 방식은 동기식, 비동기식으로 나눌 수 있습니다.

 

비동기식은 별도의 저장소를 두고 그곳에 데이터를 저장하고, 상호 데이터를 조회하는 방식입니다.

 

갑을 주고받는다기 보다는 글로벌한 곳에 데이터를 두고 상호참조하는 방식으로 이해하면 됩니다.

 

그러면 어디에 데이터를 저장하고 읽고, 쓰기를 진행하면 될까요.

 

1. AppDelegate를 이용한 접근

 

Swift의 모든 개체가 다 접근할 수 있는 AppDelegate class가 적합합니다.

 

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  
  var paramEmail: String?
  var paramUpdate: Bool?
  var param.....

여기에 변수를 정의합니다.

 

그러면 해당 데이터는 어떻게 접근할까요?

@IBAction func onSubmit(_ sender: Any){
  let ad = UIApplication.shared.delegate as? AppDelegate
  
  ad?.paramEmail = self.email.text
  ..

다음과 같이 UIAppliation에 접근해서 데이터를 바로 읽고, 쓰면 됩니다.

 

2. UserDefaults 객체를 이용한 방법

iOS에는 코코아 터치 프레임워크가 있습니다. iOS의 전통적인 프레임워크이고 swift에서도 사용이 가능합니다. 이 개체의 장점은 앱을 삭제하기 전까지는 반영구적으로 사용이 가능하다는 것입니다.

 

내부적으로 plist파일을 이용하여 값을 저장관리합니다. 기존에는 UserDefaults객체에 NSData, NSString, NSNumber와 같이 코코아 프레임워크에서 사용하는 데이타타입만 저장이 가능하지만, Swift에서는 기본 데이터타입도 저장관리가 가능해진 부분이 있습니다.

 

데이터에 읽고 쓰는 코드만으로 설명은 줄여도 될것 같습니다.

 

@IBAction func onSubmit(_ sender: Any){
  let ud = UserDefaults.standard
  
  ud.set(self.email.text, forKey: "email")
  ud.set(self.isUpdate.isOn, forKey: "isUpdate")
  ud.set(self.interval.value, forKey: "interval")
  
  self.presentingViewController?.dismiss(animated: true)
}

이 코드는 UserDefault에 데이터를 저장하게 됩니다.

 

overide func viewWillAppear(_ animated: Boole){
  let ud = UserDefaults.standard
  
  if let email = ud.string(forKey: "email") {
    resultEmail.text = email
  }
  
  let update = ud.bool(forKey: "isUpdate")
  resultUpdate.text = (update == true ? "Auto Update":"No Auto")
  
  let interval = ud.double(forKey: "interval")
  resultInterval.text = "\(Int(interval))"
}
반응형

iOS 화면전환 및 데이터 전송정리(Segue를 이용한 전환)

Computer Science/Android&iOS
반응형

4. Segue

 

Segue는 화면간의 연결을 표시하는 링크와 같다고 저는 이해했습니다. 그것의 이름이 Segue고요.

No Coding환경에서 Segue는 굳이 이름이 없어도 되는 경우가 많습니다. 하지만, 이건 기존 개발자들에게는 매우 불안한 요소입니다. 왜 불안하냐면.. 그냥 이름이 없으니까요.

 

코딩없이 우리가 Segue를 이용한것을 "Action Segue"라고 합니다. 버튼, 테이블 셀의 이벤트 트리거에 자동으로 연결이 되기 때문입니다.

Action Seguq라고 이름이 나옵니다. 오른쪽 마우스버튼으로 호출되는 메뉴입니다.

이건 굳이 우리가 프로그래밍 하지 않아도 되고, Storyboard를 통해서 직관적(?)으로 알 수 있습니다. 

사실 직관적이지는 않죠. 화면이 많으면 더더욱.. 하지만 코딩을 하지 않는것이 어디입니까.

 

이것말고 우리는 프로그램으로 제어하는 방법을 알려드리고자 합니다. 이걸 "Manual Segue"라고 합니다.

 

Action Segue는 버튼과 같은 컨트롤과 ViewController간의 관계입니다. 그렇기 때문에 해당 버튼의 동작과 연결시킬 수 있었습니다. 하지만, Manual Segue는 ViewController간의 관계를 정의해주고 이름을 명명해줘야 합니다. 역시 그림으로 설명합니다.

Manual Segue는 다음과 같이 생성합니다.

 

Action Segue는 다음과 같이 컨트롤과 Segue를 하일라이트 합니다.
Manual Segue는 ViewController를 전체로 표시합니다.

이제 우리는 Segue의 이름을 정해줘야 합니다.

Seguq의 이름은 Identifier에 넣으면 됩니다.

이제 버튼을 누르면 Segue를 통해서 화면전환하는 코드를 작성합니다. 이때 사용하는 함수와 예제 코드는 다음과 같습니다.

@IBAction func wind(_ send: Any){
  self.performSegue(withIdentifier:"ManualWind", sender:self)
}

여기서 함수 이름을 왜 wind라고 졌을까요. 지금까지 작명과는 다른데 말이죠.

 

화면전환하는 것을 iOS에서는 wind된다고 합니다. 그럼 그 반대는 unwind이겠죠.. 

 

여기서 재미있는것은 unwind되는 시점을 각각의 ViewController안에 작성해야 한다는 것입니다. 그래야 우리는 unwind되는 곳의 함수를 불러서 그쪽으로 이동하게 됩니다.

 

@IBAction func wind(_ send: Any){
  self.performSegue(withIdentifier:"ManualWind", sender:self)
}

@IBAction func unwindToVC(_ segue: UIStoryboardSegue){}

위 코드뭉치를 보면 wind를 통해서 해당 segue와 연결된 ViewController로 이동을 하게 됩니다. 그런데 복귀되는 함수도 같이 있습니다. 즉, 이 함수를 통해서 우리는 현재의 ViewController로 돌아오게 됩니다.

 

unwindToVC는 오른쪽 ViewController의 상단 "Exit"버튼과 연결됩니다.

ViewController에는 항상 위에 3개의 버튼이 있습니다. 그중에 가장 마지막에 "Exit"가 이런 unwind함수들과 연결이 됩니다.

 

unwind함수를 만드는것은 간단합니다. 함수 parameter에 (_ segue: UIStoryboardSegue) 만 정의하면됩니다. 그러면 swift가 전체 코드에서 다음과같은 parameter가 있는 함수들 리스트를 보여주고, 우리는 돌아갈 ViewController의 unwind함수만 선택하면 됩니다.

위에 그림을 보면 왼쪽에 Exit 바로 밑에 unwind가 있는것을 볼 수 있습니다.

 

버튼을 Exit와 연결시킵니다.
unwind함수들 즉 함수 parameter가 (_ segue: UIStorygoardSeguq) 인 함수리스트를 보여줍니다.

물론 전에 unwind함수를 표시하므로 내가 가야할 곳의 ViewController의 함수를 잘 선택해야 합니다.

 

휴.. 지금까지 속성으로 화면전환을 정리했습니다.

 

기존 개발자는 화면 컨트롤만으로 동작하는게 너무 힘들었습니다. 하지만, 익숙해지면 되는문제였습니다. 다만, 한번에 코드안에서 파악이 안된다는것은 아직도 생소합니다.

 

화면전환은 총 3가지 입니다.

- present(_, animated:) <-> presentingViewController.dismiss()

- navigationController.pushViewController() <-> navigationController.popViewController()

- performSegue(withIdentifier:,sender:) <-> unwind 함수

 

다음에는 화면전환시 데이터를 어떻게 주고 받는지를 정리합니다.

 

반응형

iOS 화면전환 및 데이터 전송정리(Navigation controller)

Computer Science/Android&iOS
반응형

3. 네비게이션 컨트롤러 (Navigation Controller)

 

네비게이션 컨트롤러는 다양한 페이지들이 서로 연관이 있다면 호출하고 다시 되돌아오는데 기본적인 편리성을 제공하는 View Controller입니다.

기존에 present는 화면전화 및 복귀를 내가 직접 코딩해야 했고, 복귀할때 적어도 1개의 버튼을 만들어야 했지만, Navigation Controller는 이러한 부분을 자동화 해준다고 보면됩니다.

 

기존 오래된 개발자 입장에서는 이 부분을 어떻게 이해해야 하나 고민했지만, 역시 오래보면 익숙해진다고, 그냥 익숙해지면 됩니다.

 

Navigation Controller를 만들기 위해서는 처음부터 Navigation Controller를 화면에 추가하거나, 기존의 ViewController에 Navigation Controller를 embed시키면 됩니다. 말로 풀어쓰면 어렵고, 화면을 보고 설명합시다.

 

Library입니다.

Library에서 Navigation Controller를 추가합니다. 이러면 다음과 같이

Library에서 Navigation Controller를 선택
화면에 2개의 View Controller가 표시가 됩니다.

표시가 됩니다. 기본적으로 Table View Controller가 추가가 됩니다. 여기서 Table View Controller안에 컨트롤을 삭제하고 마치 새것처럼 작업해도 됩니다. 

 

저는 이 방법보다는 기존에 사용하던 View Controller가 있다면, 거기에 Navigation Controller를 추가하는게 더 맘에 편합니다. 이 방법은

ViewController를 선택하고 메뉴에서 다음과 같은 기능을 선택합니다.

그림에 자세히 설명이 되어있습니다. View Controller를 선택하고, Editor/Embed In/Navigation Controller를 선택하면 됩니다.

 

Navigation Controller 와 연결된 View Controller들은 Navigation Item이 자동으로 생성되고, 뒤로가기가 자동으로 생성됩니다.

그렇습니다. 이렇게 자동으로 뒤로가기가 생성이 됩니다. 물론 Navigation Controller와 연결을 시켜야 하지만요.

 

연결시키는 방법은 오른쪽 마우스 버튼으로 연결시키면 됩니다.

연결여부는 여기를 통해서 확인됩니다. Show 형태로 되었습니다. 이건 뭘 의미할까요.

사실 이러한 연결은 No coding형태입니다. Present에서도 이야기 드렸듯이 코딩으로 또는 No coding으로 구현이 가능합니다.

 

위에 마우스가 아닌 버튼에 함수를 설정하면 다음과 같을 것입니다. 

 

@IBAction func moveByNavy(_ sender: Any){
  guard let uvc = self.storyboard?.instantiaterViewController(withIdentifier: "SecondVC") else{
    return
  }
  
  self.navigationController?.pushViewController(uvc, animated: true)
}

navigationController의 pushViewController(_, animated:)를 이용한것입니다. 그래서 Show(e.g. Push)로 표시가 되는 것입니다.

 

뒤로가기 위해서는 자동으로 뒤로가는 버튼이 생성이 됩니다. 물론 이것도 우리는 코딩으로 처리할 수 있습니다.

 

@IBAction func back(_ sender: Any){
  self.navigationController?.popViewController(animated: true)
}

여기서 조심해야 할것은 NavigationController를 이용하게 되면 우리 의지와는 상관없이 NavigationItem이 추가로 생성되고, 왼쪽에 뒤로가기 버튼이 자동으로 생성된다는 것입니다. UI충돌을 막기 위해서는 View Controller의 왼쪽상단에 Navigation Item이 생성되는것을 고려한 UI디자인이 필요합니다.

반응형