Language/iOS,AOS
iOS 애플 로그인
건담아빠
2023. 4. 11. 18:53
웹뷰를 사용하는 환경에서 웹 소스에서 bridge를 통해 iOS에서 로그인 인증을 받는 부분을 정리하려고 합니다.
1. 애플 개발자 사이트 설정
Apple Developer
There’s never been a better time to develop for Apple platforms.
developer.apple.com
아래와 같이 Account -> Identifiers -> Sign In with Apple 추가 후 프로비저닝 프로파일 다시 내려받아서 적용합니다.
2. Capablility 추가
`+` 를 눌러서 Sign In with Apple를 추가합니다.
3. 코드
3.1. Swift 코드
import AuthenticationServices
...
// MARK: - iOS Bridge
// 웹 액션 정의 : WebAction을 구분하는데 사용되는 타입
enum WebAction: String {
...
case loginWithKakao
case loginWithNaver
case loginWithFacebook
case loginWithApple
...
}
...
extension MainViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard message.name == IOS_BRIDGE_NAME,
let messages = message.body as? [String: Any],
let action = messages["action"] as? String else { return }
let webAction = WebAction(rawValue: action)
switch webAction {
...
case .loginWithApple:
guard let params: [String: Any] = messages["params"] as? [String: Any],
let callback: String = params["callback"] as? String else {
return
}
loginWithApple(callback: callback)
...
default:
Utils.Log("undefined action")
}
}
}
...
// MARK: - 애플 로그인 - 확장
extension MainViewController: ASAuthorizationControllerDelegate {
/**
* 로그인 및 체크
*/
func loginWithApple(callback: String) -> Void {
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
// authorizationController.presentationContextProvider = self
authorizationController.performRequests()
}
// 성공 후 동작
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
let idToken = credential.identityToken!
guard let idTokenStr: String = String(data: idToken, encoding: .utf8) else {
return
}
guard let code = credential.authorizationCode else { return }
let codeStr = String(data: code, encoding: .utf8)
let user = credential.user
let callback = "window.setAccessToken"
self.executeJavasScript(wKWeb: self.getActiveWkWebView(), callback: "\(callback)('\(idTokenStr)')")
}
}
// 실패 후 동작
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
Utils.Log("##################### didCompleteWithError : \(error)")
}
}
3.2. 일반웹
const loginByWeb = function () {
...
}
sessionStorage.setItem(Common.POST_LOGIN_URI, location.pathname + location.search);
if (Util.Browser.isAndroidApp()) {
...
} else if (Util.Browser.isIosApp()) {
window.setAccessToken = function (idToken) {
if (idToken === 'cancel') {
} else if (idToken === 'error') {
loginByWeb();
} else if (idToken) {
Common.login({
SNS_TYPE_CD: 'SNSTP00004',
id_token: encodeURIComponent(idToken)
})
} else {
loginByWeb();
}
}
const message = {
action: 'loginWithApple',
params: {callback: 'window.setAccessToken'}
};
window.webkit.messageHandlers.IosBridge1.postMessage(message);
} else {
loginByWeb();
}
3.3. 리엑트
export const useLogin = () => {
const context = useContext(BaseContext);
const kakao = () => {
...
};
const apple = () => {
...
const loginByWeb = function () {
...
};
if (Util.Browser.isIosApp()) {
window.setAccessToken = async function (idToken) {
context.showLoading(false);
if (idToken === 'cancel') {
} else if (idToken === 'error') {
loginByWeb();
} else if (idToken) {
await Common.login({ SNS_TYPE_CD: 'SNSTP00004', id_token: encodeURIComponent(idToken) });
} else {
loginByWeb();
}
context.showLoading(false);
};
try {
const message = {
action: 'loginWithApple',
params: { callback: 'window.setAccessToken' },
};
window.webkit.messageHandlers.IosBridge1.postMessage(message);
} catch (e) {
loginByWeb();
}
} else {
setTimeout(() => {
loginByWeb();
}, 500);
}
...
};
return { kakao, apple };
};
<a
className={cx('btn_apple')}
onClick={() => {
props.onClose();
login.apple();
}}
>
Apple로 계속하기
</a>
짝짝짝