-
iOS 앱 간의 통신을 구현하기iOS 2018. 8. 18. 23:22반응형
통신을 부르는 앱을 A, 실행되는 앱을 B라고 하면
B에서는 info.plist에 다음과 같이 추가를 해 주어야 합니다.
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>test</string>
</array>
</dict>
</array>
이제 다른 앱에서
URL Scheme가 'test' 인 URL을 오픈하면, B 앱이 실행되게 됩니다.
이제 A 앱에서 B 앱을 부를 차례입니다.
스키마를 'test'로 지정해주고 콜하면 일단 B 앱은 부를 수 있지만, 무슨 목적으로 B 앱을 불렀는지도 같이 넘겨 주어야 합니다.
따라서 호스트나 쿼리 형식으로 기타 정보를 같이 넘겨줍니다.
var components = URLComponents()
components.scheme = panService.serviceCode
components.host = "tester_host" //호스트에는 어떤 목적으로 쐈는지 표시해 주었습니다.
components.queryItems = [URLQueryItem(name: "sender", value: AppText.app_service_code)] // 누가 보냈는지 같이 쏴 줍니다.
guard let schemeURL = components.url else {
return
}
if UIApplication.shared.canOpenURL(schemeURL) {
print(schemeURL)
UIApplication.shared.open(schemeURL, options: [:]) { (bool) in
print(bool)
}
}else {
self.alert("B 앱이이 현재 설치되어 있지 않은 상태이므로, 실행할 수 없습니다.")
}
실행되는 B 앱에서는 A 앱이 B 앱을 불러왔다는 것을 감지하고, 일반적인 실행과 다른 모습을 보여야 합니다.
AppDelegate에 func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool 함수에 다음과 같은 부분을 추가해 줍니다. 저는 B 앱의 BViewController() 뷰컨트롤러에서 해당 부분을 처리하기로 했으므로, 강제로 BViewController 를 root로 해 주는 방식으로 해 주었습니다.
@available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if (url.scheme == 'test'){
if (url.host == "tester_auth"){
let vc = BViewController()
vc.openUrl = url // url을 같이 보내줍니다.
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
return true
}
}
*** 이전 코드들을 이어 줍니다.
if KOSession.isKakaoAccountLoginCallback(url){
return KOSession.handleOpen(url)
}
guard let scheme = url.scheme else{
return false
}
if scheme == NaverKey.serviceUrlScheme {
return NaverThirdPartyLoginConnection.getSharedInstance().application(app, open: url, options: options)
/*if result == .CANCELBYUSER{
}*/
}
if scheme == FacebookKey.serviceUrlScheme {
SDKApplicationDelegate.shared.application(app, open:url, options: options)
}
return GIDSignIn.sharedInstance().handle(url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String, annotation: [:])
//return SDKApplicationDelegate.shared.application(app, open:url, options: options)
}
BViewController에서는 전송받은 url을 해석해 원하는 행동을 해 줍니다.
모든 행동을 다 끝냈으면, B 앱은 정상적으로 앱 사이클을 돌아야 합니다. 따라서 정상적인 스토리보드의 뷰컨트롤러를 탈 수 있도록 다음 함수를 콜 해 줍니다.
func goToLauncher() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
UIApplication.shared.keyWindow?.rootViewController = storyboard.instantiateInitialViewController()
}
다만, B 앱에서 하는 일이 마음에 안 들어 유저가 행동을 취소할 수도 있겠죠.
이 경우, A 앱으로 돌아가는 액션도 구현이 필요합니다.
취소는 B 앱이 A 앱을 실행시키는 것으로 구현해야 합니다. A 앱에서 B 앱으로 실행하는 것처럼 info.plist에서 등록했던 것을 되짚어 A 앱에도 info.plist에 스키마를 등록합니다.
@IBAction func cancelAuth(_ sender: Any) {
var components = URLComponents()
components.scheme = self.sender!
guard let schemeURL = components.url else {
return
}
if UIApplication.shared.canOpenURL(schemeURL) {
print(schemeURL)
UIApplication.shared.open(schemeURL, options: [:]) { (bool) in
print(bool)
self.goToLauncher()
}
}else {
self.goToLauncher()
}
}
(A 앱에서 취소 액션 처리하기)
A 앱의 델리게이트에 다음과 같이 구현합니다. 그러면 B 앱이 A 앱으로 다시 돌아갔을 때,
이를 감지하고 'OpenCanceled' 라는 커스텀 노티피케이션을 전송할 수 있을 것입니다. 노티피케이션엔 겸사겸사 url도 넣어 줍니다.
@available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if (url.scheme == 'test_cancel'){
if (url.host == "cancel"){
print("called this")
var userinfo = [AnyHashable : Any]()
userinfo["url"] = url
NotificationCenter.default.post(
name: Notification.Name(rawValue: "OpenCanceled"), object: nil, userInfo: userinfo
)
}
}
A 앱에서 B 앱으로 접속했던 뷰 컨트롤러에 해당 노티피케이션을 해석하는 부분을 구현합니다.
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
NotificationCenter.default.addObserver(self, selector: #selector(cancelCallBack), name: Notification.Name(rawValue: "OpenCanceled")
, object: nil)
}
@objc func cancelCallBack(notification: Notification){
print(notification)
if let userInfo = notification.userInfo {
if let url = userInfo["url"] as? URL {
... url을 해석해 취소 부분을 해석합니다.
}
}
}
반응형'iOS' 카테고리의 다른 글
iOS 텍스트가 비었으면 확인 버튼 비활성하는 UIAlertController 생성 (1) 2018.09.02 주니어 / 미들 / 시니어 레벨 iOS 개발자를 구분하는 기술 일람 (0) 2018.08.19 Alamofire를 이용한 api service 설계 (0) 2018.08.12 UICollectionView서 헤더로 다이나믹하게 높이 계산하는 로직 (UITextView) 넣기 (0) 2018.07.25 [swift]WKWebview 스크롤 맨 아래로 정확하게 계산해서 내리기 (0) 2018.07.25