Skip to content

Commit

Permalink
Merge pull request #341 from TeamNADA/feature/#338
Browse files Browse the repository at this point in the history
feat: 앱 내에서 동적링크 생성 (#338)
  • Loading branch information
hyun99999 authored Jan 8, 2023
2 parents e228545 + 07b9ef6 commit 9ddaaf4
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 45 deletions.
10 changes: 10 additions & 0 deletions NADA-iOS-forRelease.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
F82FF8262702000000E57F8B /* RequiredFlavorCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F82FF8242702000000E57F8B /* RequiredFlavorCollectionViewCell.xib */; };
F83206AA26F61E3700D61711 /* FrontCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F83206A826F61E3700D61711 /* FrontCardCell.swift */; };
F83206AB26F61E3700D61711 /* FrontCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F83206A926F61E3700D61711 /* FrontCardCell.xib */; };
F837AB7D2965582C00A8804A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F837AB7C2965582C00A8804A /* GoogleService-Info.plist */; };
F84BAF9D26FDB417004CA335 /* CardCreationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84BAF9C26FDB417004CA335 /* CardCreationViewController.swift */; };
F84BAFAD26FDB543004CA335 /* FrontCardCreationCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F84BAFAB26FDB543004CA335 /* FrontCardCreationCollectionViewCell.swift */; };
F84BAFAE26FDB543004CA335 /* FrontCardCreationCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F84BAFAC26FDB543004CA335 /* FrontCardCreationCollectionViewCell.xib */; };
Expand Down Expand Up @@ -250,6 +251,7 @@
F82FF8242702000000E57F8B /* RequiredFlavorCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RequiredFlavorCollectionViewCell.xib; sourceTree = "<group>"; };
F83206A826F61E3700D61711 /* FrontCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrontCardCell.swift; sourceTree = "<group>"; };
F83206A926F61E3700D61711 /* FrontCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FrontCardCell.xib; sourceTree = "<group>"; };
F837AB7C2965582C00A8804A /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
F84BAF9C26FDB417004CA335 /* CardCreationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardCreationViewController.swift; sourceTree = "<group>"; };
F84BAFAB26FDB543004CA335 /* FrontCardCreationCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrontCardCreationCollectionViewCell.swift; sourceTree = "<group>"; };
F84BAFAC26FDB543004CA335 /* FrontCardCreationCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FrontCardCreationCollectionViewCell.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -800,6 +802,7 @@
F8FC439926C01E2B0033E151 /* Resouces */ = {
isa = PBXGroup;
children = (
F837AB7C2965582C00A8804A /* GoogleService-Info.plist */,
F857FC8A26C03A5C00A48D01 /* Assets */,
39DA4D7B2747D7060082D572 /* Font */,
F8FC43A326C01F420033E151 /* Constants */,
Expand Down Expand Up @@ -1049,6 +1052,7 @@
F82FF81D2701EBCE00E57F8B /* CardCreation.storyboard in Resources */,
39369937274A4FCB00684420 /* NotoSansCJKkr-Medium.otf in Resources */,
392F7FB5274621F1008CDBF5 /* MoreListTableViewCell.xib in Resources */,
F837AB7D2965582C00A8804A /* GoogleService-Info.plist in Resources */,
7770315927500C49002CBD19 /* QRScan.storyboard in Resources */,
390515B82706CEBB00C5F7A5 /* Colors.xcassets in Resources */,
);
Expand Down Expand Up @@ -1357,9 +1361,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "NADA-iOS-forRelease/NADA-iOS-forRelease.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = T3VFJ764ZC;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = T3VFJ764ZC;
INFOPLIST_FILE = "NADA-iOS-forRelease/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -1369,6 +1375,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "YJC.NADA-iOS-forRelease";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match Development YJC.NADA-iOS-forRelease";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match Development YJC.NADA-iOS-forRelease";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand All @@ -1382,9 +1389,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "NADA-iOS-forRelease/NADA-iOS-forRelease.entitlements";
CODE_SIGN_IDENTITY = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = T3VFJ764ZC;
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = T3VFJ764ZC;
INFOPLIST_FILE = "NADA-iOS-forRelease/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
Expand All @@ -1394,6 +1403,7 @@
PRODUCT_BUNDLE_IDENTIFIER = "YJC.NADA-iOS-forRelease";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore YJC.NADA-iOS-forRelease";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore YJC.NADA-iOS-forRelease";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
};
Expand Down
4 changes: 4 additions & 0 deletions NADA-iOS-forRelease/NADA-iOS-forRelease.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@
<array>
<string>Default</string>
</array>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:itznada.page.link</string>
</array>
</dict>
</plist>
4 changes: 4 additions & 0 deletions NADA-iOS-forRelease/Resouces/Constants/URL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ extension Const {
static let keyboardURL = "https://github.com/hackiftekhar/IQKeyboardManager"
static let kingfisherURL = "https://github.com/onevcat/Kingfisher"
static let indicatorURL = "https://github.com/ninjaprox/NVActivityIndicatorView"
static let dynamicLinkURLPrefix = "https://itznada.page.link"

// FIXME: - 동적링크를 웹에서 여는 경우 홍보 페이지로 이동할 수 있는 URL 로 릴리즈 전에 변경. 현재 과거 홍보 페이지 URL 로 설정해둠.
static let opendDynamicLinkOnWebURL = "https://www.notion.so/nadaitzme/NADA-22c9c7fc3e00453fa12d885e6e58fe86"
}
}
34 changes: 34 additions & 0 deletions NADA-iOS-forRelease/Resouces/GoogleService-Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>900084768088-b2bb5tkqu6ar55j05fn07aacaept7ahi.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.900084768088-b2bb5tkqu6ar55j05fn07aacaept7ahi</string>
<key>API_KEY</key>
<string>AIzaSyCgjeaGYq8lcEYim6AfrBDs0rKCOPvcnVs</string>
<key>GCM_SENDER_ID</key>
<string>900084768088</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>YJC.NADA-iOS-forRelease</string>
<key>PROJECT_ID</key>
<string>nada-7f9c8</string>
<key>STORAGE_BUCKET</key>
<string>nada-7f9c8.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:900084768088:ios:a52d55f364646a8931592d</string>
</dict>
</plist>
6 changes: 5 additions & 1 deletion NADA-iOS-forRelease/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
// Created by kimhyungyu on 2021/08/08.
//

import AuthenticationServices
import UIKit

import Firebase
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import AuthenticationServices

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
Expand All @@ -18,6 +20,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

FirebaseApp.configure()

KakaoSDK.initSDK(appKey: "5b8dd8cc878344bb7532eeca4365a4aa")

Expand Down
34 changes: 31 additions & 3 deletions NADA-iOS-forRelease/Sources/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//

import UIKit

import FirebaseDynamicLinks
import IQKeyboardManagerSwift
import KakaoSDKAuth

Expand Down Expand Up @@ -36,7 +38,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window.overrideUserInterfaceStyle = .light
}
}


if let userActivity = connectionOptions.userActivities.first {
self.scene(scene, continue: userActivity)
}
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
Expand All @@ -47,6 +52,18 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}
}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let url = userActivity.webpageURL {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(url) { dynamicLink, error in
if let cardID = self.handleDynamicLink(dynamicLink) {

// TODO: - user defaults 로 cardID 저장하고, 홈 뷰에서 존재 유무로 명함 조회. 조회 시 user defaults 삭제.

}
}
}
}

// MARK: - Methods

func sceneDidDisconnect(_ scene: UIScene) {
Expand Down Expand Up @@ -76,7 +93,18 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}


}

// MARK: - Extensions

extension SceneDelegate {
private func handleDynamicLink(_ dynamicLink: DynamicLink?) -> String? {
guard let dynamicLink = dynamicLink,
let link = dynamicLink.url else { return nil }

let queryItems = URLComponents(url: link, resolvingAgainstBaseURL: true)?.queryItems
let cardID = queryItems?.filter { $0.name == "cardID" }.first?.value

return cardID
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import UIKit
import Photos

import FirebaseDynamicLinks

class CardShareBottomSheetViewController: CommonBottomSheetViewController {

// MARK: - Properties
Expand Down Expand Up @@ -63,13 +65,14 @@ class CardShareBottomSheetViewController: CommonBottomSheetViewController {
}()

// MARK: - View Life Cycle

override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}

// MARK: - @Functions
// UI 세팅 작업

private func setupUI() {
idStackView.addArrangedSubview(idTitleLabel)
idStackView.addArrangedSubview(idLabel)
Expand All @@ -85,7 +88,6 @@ class CardShareBottomSheetViewController: CommonBottomSheetViewController {
setQRImage()
}

// 레이아웃 세팅
private func setupLayout() {
qrImage.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
Expand All @@ -111,12 +113,43 @@ class CardShareBottomSheetViewController: CommonBottomSheetViewController {

private func setQRImage() {
let frame = CGRect(origin: .zero, size: qrImage.frame.size)
print("TeamNADA\(cardDataModel?.cardID ?? "")")
let qrcode = QRCodeView(frame: frame)
qrcode.generateCode("ThisIsTeamNADAQrCode\(cardDataModel?.cardID ?? "")",
foregroundColor: .primary,
backgroundColor: .background)
qrImage.addSubview(qrcode)
generateDynamicLink(with: cardDataModel?.cardID ?? "") { dynamicLink in

// FIXME: - ThisIsTeamNADAQrCode 로 나다에서 prefix 파악하는데 수정하기

qrcode.generateCode(dynamicLink,
foregroundColor: .primary,
backgroundColor: .background)
self.qrImage.addSubview(qrcode)
}
}

private func generateDynamicLink(with cardID: String, completion: @escaping ((String) -> Void)) {
guard let link = URL(string: Const.URL.opendDynamicLinkOnWebURL + "/?cardID=" + cardID),
let bundleID = Bundle.main.infoDictionary?["CFBundleIdentifier"] as? String else { return }
let domainURLPrefix = Const.URL.dynamicLinkURLPrefix
let appStoreID = "1600711887"

let linkBuilder = DynamicLinkComponents(link: link, domainURIPrefix: domainURLPrefix)

linkBuilder?.iOSParameters = DynamicLinkIOSParameters(bundleID: bundleID)
linkBuilder?.iOSParameters?.appStoreID = appStoreID
linkBuilder?.navigationInfoParameters = DynamicLinkNavigationInfoParameters()
linkBuilder?.navigationInfoParameters?.isForcedRedirectEnabled = true

var dynamicLink: String = ""

linkBuilder?.options = DynamicLinkComponentsOptions()
linkBuilder?.options?.pathLength = .short

linkBuilder?.shorten { url, warnings, error in
if let url {
dynamicLink = "\(url)"
}

completion(dynamicLink)
}
}

private func setImageWriteToSavedPhotosAlbum() {
Expand All @@ -129,10 +162,10 @@ class CardShareBottomSheetViewController: CommonBottomSheetViewController {
UIImageWriteToSavedPhotosAlbum(backCardImage, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
case .denied:
makeOKCancelAlert(title: "갤러리 권한이 허용되어 있지 않아요.",
message: "명함 이미지 저장을 위해 갤러리 권한이 필요합니다. 앱 설정으로 이동해 허용해 주세요.",
okAction: { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)},
cancelAction: nil,
completion: nil)
message: "명함 이미지 저장을 위해 갤러리 권한이 필요합니다. 앱 설정으로 이동해 허용해 주세요.",
okAction: { _ in UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)},
cancelAction: nil,
completion: nil)
case .notDetermined:
PHPhotoLibrary.requestAuthorization({state in
if state == .authorized {
Expand Down Expand Up @@ -168,6 +201,7 @@ class CardShareBottomSheetViewController: CommonBottomSheetViewController {

return frontImage
}

private func setBackCardImage() -> UIImage {
guard let backCard = BackCardCell.nib().instantiate(withOwner: self, options: nil).first as? BackCardCell else { return UIImage() }
backCard.frame = CGRect(x: 0, y: 0, width: 327, height: 540)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class SelectBirthBottomSheetViewController: CommonBottomSheetViewController {
private let doneButton: UIButton = {
let button = UIButton()
button.setImage(UIImage(named: "btnMainDone"), for: .normal)
button.addTarget(SelectBirthBottomSheetViewController.self, action: #selector(dismissToCardCreationViewController), for: .touchUpInside)
button.addTarget(self, action: #selector(dismissToCardCreationViewController), for: .touchUpInside)

return button
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import UIKit
import AVFoundation

import FirebaseDynamicLinks

class QRScanViewController: UIViewController {

// MARK: - Properties
Expand Down Expand Up @@ -118,25 +120,27 @@ extension QRScanViewController {
}

extension QRScanViewController: AVCaptureMetadataOutputObjectsDelegate {

func metadataOutput(_ captureOutput: AVCaptureMetadataOutput,
didOutput metadataObjects: [AVMetadataObject],
from connection: AVCaptureConnection) {

if let metadataObject = metadataObjects.first {

guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject, let stringValue = readableObject.stringValue else {
return
}

// ✅ qr코드가 가진 문자열이 URL 형태를 띈다면 출력.(아무런 qr코드나 찍는다고 출력시키면 안되니까 여기서 분기처리 가능. )
if stringValue.hasPrefix("ThisIsTeamNADAQrCode") {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject,
let stringValue = readableObject.stringValue,
let stringValueURL = URL(string: stringValue) else { return }

if stringValue.hasPrefix(Const.URL.dynamicLinkURLPrefix) {
self.captureSession.stopRunning()
// TODO: 여기서 QR에 있는 ID값으로 명함검색 API통신
cardDetailFetchWithAPI(cardID: stringValue.deletingPrefix("ThisIsTeamNADAQrCode"))

DynamicLinks.dynamicLinks().handleUniversalLink(stringValueURL) { dynamicLink, error in
guard let url = dynamicLink?.url else { return }
let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: true)?.queryItems
let cardID = queryItems?.filter { $0.name == "cardID" }.first?.value

self.cardDetailFetchWithAPI(cardID: cardID ?? "")
}
} else {
showToast(message: "유효하지 않은 QR입니다.", font: UIFont.button02, view: "QRScan")
self.showToast(message: "유효하지 않은 QR입니다.", font: UIFont.button02, view: "QRScan")
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ pod 'KakaoSDKAuth'
pod 'IQKeyboardManagerSwift'
pod 'Kingfisher', '~> 7.0'
pod 'NVActivityIndicatorView'
pod 'Firebase/DynamicLinks'
end
Loading

0 comments on commit 9ddaaf4

Please sign in to comment.