カスタム URL を使った実装
URLのルール
<アプリのカスタムURIスキーム名>://jp.popinfo.coupon/coupons/?key=<VALUE>&key2=<VALUE2>
下記は
coupon.sampleというカスタムURLスキームを受取り、クーポン一覧画面を表示する場合の例になります。
"coupon.sample://jp.popinfo.coupon/coupons/?uuid=xxx&action=distribute"
設定方法
info.plistを開いて、以下のように「URL types」->「URL Schemes」の項目にカスタムURLスキームを設定してください。
URL identifireは端末内でユニークな識別文字列を設定してください。
URL Schemesは複数指定可能です。ここでは、sample://というカスタムURLスキームを想定して設定します。

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>fanship.coupon.sample</string>
<key>CFBundleURLSchemes</key>
<array>
<string>coupon.sample</string>
</array>
</dict>
</array>
実装方法
rootViewControllerの取得方法
下記のメソッドを利用して取得します。
func getRootViewController() -> UIViewController? {
if let windowScene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
return windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController
}
return UIApplication.shared.delegate?.window??.rootViewController
}
SceneDelegateを利用する場合
1. カスタムURLスキームを格納する変数を定義
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var customUrl: URL? // カスタムURLスキームを格納する
...
2. アプリが閉じている場合、受取ったカスタムURLスキームを格納
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
// アプリが閉じている場合、カスタムURLスキームを確認
customUrl = connectionOptions.urlContexts.first?.url
}
3. シーンがアクティブ状態になった際に限定クーポンを配布して一覧へ画面遷移
func sceneDidBecomeActive(_ scene: UIScene) {
...
// カスタムURLスキームを確認
guard let url = customUrl else { return }
customUrl = nil
guard let userId = PopinfoReceiver.shared.userId else { return }
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true)
// URLからクーポンのuuidを取得
if let uuid = urlComponents?.queryItems?.first?.value {
// FanshipCouponClientの初期化
FanshipCouponClient.sharedInstance().initWithServiceId("your_service_id")
// 限定クーポンの配布メソッドを呼び出し
FanshipCouponClient.sharedInstance().distributeCoupon(withUserId: userId, couponUUID: uuid) { response, error in
Task { @MainActor in
if let error {
// 限定クーポン配布エラー時の処理
} else if let response {
// 限定クーポン配布が成功した場合に、CouponListViewControllerのインスタンスを作成
let vc = CouponListViewController(serviceId: "your_service_id", userId: userId, uuid: response.coupon?.uuid)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
}
}
}
}
}
4. アプリ内で呼ばれた場合に限定クーポンを配布して一覧へ画面遷移
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
// カスタムURLスキームを確認
customUrl = URLContexts.first?.url
// アプリ内で呼ばれた場合の処理
if Bundle.main.bundleIdentifier == URLContexts.first?.options.sourceApplication {
guard let url = customUrl else { return }
customUrl = nil
guard let userId = PopinfoReceiver.shared.userId else { return }
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true)
// URLからクーポンのuuidを取得
if let uuid = urlComponents?.queryItems?.first?.value {
// FanshipCouponClientの初期化
FanshipCouponClient.sharedInstance().initWithServiceId("your_service_id")
// 限定クーポンの配布メソッドを呼び出し
FanshipCouponClient.sharedInstance().distributeCoupon(withUserId: userId, couponUUID: uuid) { response, error in
Task { @MainActor in
if let error {
// 限定クーポン配布エラー時の処理
} else if let response {
// 限定クーポン配布が成功した場合に、CouponListViewControllerのインスタンスを作成
let vc = CouponListViewController(serviceId: "your_service_id", userId: userId, uuid: response.coupon?. uuid)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
}
}
}
}
}
}
SceneDelegateを利用しない場合
AppDelegate内のopen urlメソッドで、URLからアプリを起動した時の処理を追加してください。
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true)
// URLからクーポンのuuidを取得
if let uuid = urlComponents?.queryItems?.first?.value {
// ユーザーIDは FANSHIP SDK から取得できます
if let userId = PopinfoReceiver.shared.userId {
// FanshipCouponClientの初期化
FanshipCouponClient.sharedInstance().initWithServiceId("your_service_id")
// 限定クーポンの配布メソッドを呼び出し
FanshipCouponClient.sharedInstance().distributeCoupon(withUserId: userId, couponUUID: uuid) { response, error in
Task { @MainActor in
if let error {
// 限定クーポン配布エラー時の処理
} else if let response {
// 限定クーポン配布が成功した場合に、CouponListViewControllerのインスタンスを作成
let vc = CouponListViewController(serviceId: "your_service_id", userId: userId, uuid: response.coupon?. uuid)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
}
}
}
}
}
return true
}
実装例
カスタムURLスキームを利用した実装例について紹介します。
- クーポン詳細画面を開く(open)
- クーポン配布を行った後、クーポン一覧画面へ遷移する(distribute)
- クーポン配布を行った後、クーポン詳細画面へ遷移する(openOnDistribution)
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true)
// URLからクーポンのuuidを取得
if let uuid = urlComponents?.queryItems?.first?.value {
// URLからクーポンのactionを取得
if let action = urlComponents?.queryItems?[1].value {
if action == "distribute" {
// ユーザーIDは FANSHIP SDK から取得できます
if let userId = PopinfoReceiver.shared.userId {
FanshipCouponClient.sharedInstance().distributeCoupon(withUserId: userId, couponUUID: uuid) { response, error in
Task { @MainActor in
if let error {
// 限定クーポン配布エラー時の処理
} else if let response {
// 限定クーポン配布が成功した場合に、CouponListViewControllerのインスタンスを作成
let vc = CouponListViewController(serviceId: "your_service_id", userId: userId, uuid: response. coupon?. uuid)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
}
}
}
}
} else if action == "open" {
// クーポン一覧から該当クーポンを検索
searchCoupon(page: page, uuid: uuid)
} else if action == "openOnDistribution" {
// ユーザーIDは FANSHIP SDK から取得できます
if let userId = PopinfoReceiver.shared.userId {
FanshipCouponClient.sharedInstance().distributeCoupon(withUserId: userId, couponUUID: uuid) { response, error in
Task { @MainActor in
if let error {
// 限定クーポン配布エラー時の処理
} else if let response {
// 限定クーポン配布が成功した場合に、CouponListViewControllerのインスタンスを作成
let vc = CouponListViewController(serviceId: "your_service_id", userId: userId, uuid: response. coupon?. uuid)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
}
}
}
}
}
}
}
return true
}
func searchCoupon(page: Int, uuid: String) {
if let userId = PopinfoReceiver.shared.userId {
FanshipCouponClient.sharedInstance().getCouponList(withUserId: userId, sortKey: FanshipCouponSortKey.priority,order: false, page: page, providers: nil) { response, error in
Task { @MainActor in
if let error {
// エラー処理
} else if let response {
if response.coupons.count != 0 {
var shouldContinue: Bool = true
for coupon: FanshipCoupon in response.coupons {
if !FanshipCouponUtils.isCouponUsed(coupon) && coupon.uuid.hasPrefix(uuid) {
// CouponDetailViewControllerのインスタンスを作成
let vc = CouponDetailViewController(uuid: coupon.uuid, userId: userId)
// UINavigationControllerを利用する場合の画面遷移
guard let navigation: UINavigationController = getRootViewController() as? UINavigationController else { return }
navigation.popToRootViewController(animated: false)
navigation.pushViewController(vc, animated: true)
shouldContinue = false
self.page = 1
break
}
}
if shouldContinue {
self.page += 1
self.searchCoupon(page: self.page, uuid: uuid)
}
} else {
self.page = 1
}
}
}
}
}
}