コンテンツにスキップ

カスタム URL を使った実装

このページでは管理画面で限定クーポンを作成した際に発行されるカスタム URL による配布方法を説明します。
※限定クーポンについての詳細はこちらをご確認ください

カスタム URL の設定

限定クーポンをカスタム URL 経由で受け取る場合、カスタム URL スキームを設定する必要があります。
AndroidManifest.xml に intent-filter でカスタム URL スキームを設定し、遷移する画面を指定してください。

下記のサンプルコードでは coupon.sample というカスタム URL スキームを受け取った場合に LinkActivity に遷移し、クーポン一覧画面を表示するという処理を行います。

...

<activity
    android:name=".LinkActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="coupon.sample" />
    </intent-filter>
</activity>

...
<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".LinkActivity">

<FrameLayout
    android:id="@+id/fanship_coupon_container_list"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

<FrameLayout
    android:id="@+id/fanship_coupon_container_detail"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

詳細遷移 や 配布 API の実行

カスタム URL 経由で画面を開いた際に
①クーポン詳細を表示するサンプル(open)
②クーポン配布を行い一覧画面へ遷移するサンプル(distribute)
③クーポン配布を行いクーポン詳細を表示するサンプル(openOnDistribution) となります。

class LinkActivity : AppCompatActivity() {

private var userId = ""
private val URL_HOST = "jp.popinfo.coupon"
private val PARAM_ACTION = "action"
private val ACTION_OPEN = "open"
private val ACTION_DISTRIBUTE = "distribute"
private val ACTION_OPEN_ON_DISTRIBUTE = "openOnDistribution"
private var pageForFindDistributionId = 1

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_link)

    userId = Popinfo.getUserId(this)
    showCouponListFragment()
    handleIntent(intent)
}

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    handleIntent(intent)
}

private fun handleIntent(intent: Intent?) {
    // カスタム URL 経由で無い場合は処理を抜ける
    if (intent == null || Intent.ACTION_VIEW != intent.action) {
        return
    }

    // ULIを取得
    val uri = intent.data ?: return

    // action指定が無い場合は処理を抜ける
    if (uri.getQueryParameter(PARAM_ACTION) == null) {
        return
    }

    // クーポン配布用カスタム URL の判断
    val authority = uri.authority
    if (authority != URL_HOST) {
        return
    }

    // uuidが無い場合は処理を抜ける
    val uuid = uri.getQueryParameter("uuid") ?: return

    // Actionごとに処理を分離
    val action = intent.data!!.getQueryParameter(PARAM_ACTION)
    if (action == ACTION_OPEN) {
        // ①クーポン詳細を表示するサンプル(open)
        handleOpenAction(uuid)
    } else if (action == ACTION_DISTRIBUTE) {
        // ②クーポン配布を行い一覧画面へ遷移するサンプル(distribute)
        handleDistributeAction(uuid)
    } else if (action == ACTION_OPEN_ON_DISTRIBUTE) {
        // ③クーポン配布を行いクーポン詳細を表示するサンプル(openOnDistribution)
        handleOpenOnDistributionAction(uuid)
    }
}

/**
 * ①クーポン詳細を表示するサンプル(open)
 */
private fun handleOpenAction(uuid: String) {
    // クーポン一覧を取得
    FanshipCouponClient.getCouponList(
        this,
        userId,
        FanshipCouponClient.SortEnum.USABLE_END_DATE,
        true,
        pageForFindDistributionId,
        null,
        object : FanshipCouponAsyncCallback<FanshipCouponListResponse> {
            // クーポン一覧の取得に成功した場合
            override fun onComplete(couponResponse: FanshipCouponListResponse) {
                var targetId: String? = null
                val hasNextPage = couponResponse.couponList.isNotEmpty()

                // 対象のクーポンが一覧に含まれているかをForループで検索
                for (i in couponResponse.couponList.indices) {
                    val coupon = couponResponse.couponList[i]

                    // UUIDが一致 かつ使用済みではない場合
                    if (coupon.uuid.startsWith(uuid) && !FanshipCouponUtils.isUsedCoupon(coupon)) {
                        // TargetIDとして取り出す
                        targetId = coupon.uuid
                        break
                    }
                }

                // TargetIDがNUllではない場合(上の処理で見つかった場合)
                if (targetId != null) {
                    val finalTargetId: String = targetId
                    runOnUiThread {
                        // クーポン詳細を表示
                        showCouponDetail(finalTargetId)
                        pageForFindDistributionId = 1
                    }
                // 次ページが存在している場合
                } else if (hasNextPage) {
                    // ページ番号を加算し同じ処理を最初から繰り返す
                    pageForFindDistributionId++
                    handleOpenAction(uuid)
                } else {
                    // 次ページがページが存在しない場合は終了
                    finish()
                }
            }
            // クーポン一覧の取得に失敗した場合
            override fun onError(e: FanshipCouponErrorException) {}
        },
    )
}

/**
 * ②クーポン配布を行い一覧画面へ遷移するサンプル(distribute)
 */
private fun handleDistributeAction(couponUuid: String) {
    // クーポン配布 API を実行
    FanshipCouponClient.distributeCoupon(
        applicationContext,
        Popinfo.getPopinfoId(applicationContext),
        couponUuid!!,
        object : FanshipCouponAsyncCallback<FanshipCouponDistributeResponse> {
            // クーポンの配布に成功した場合
            override fun onComplete(response: FanshipCouponDistributeResponse) {
                // クーポン一覧画面へ遷移
                if (response.coupon != null) {
                    val _intent = Intent(
                        applicationContext,
                        FanshipCouponList::class.java,
                    )
                    _intent.putExtra(DISTRIBUTE_ID, response.coupon.uuid)
                    startActivity(_intent)
                }

                finish()
            }

            // クーポンの配布に失敗した場合
            override fun onError(e: FanshipCouponErrorException) {
                finish()
            }
        },
    )
}

/**
 * ③クーポン配布を行いクーポン詳細を表示するサンプル(openOnDistribution)
 */
private fun handleOpenOnDistributionAction(couponUuid: String) {
    FanshipCouponClient.distributeCoupon(
        applicationContext,
        Popinfo.getPopinfoId(applicationContext),
        couponUuid,
        object : FanshipCouponAsyncCallback<FanshipCouponDistributeResponse> {
            // クーポン配布に成功した場合
            override fun onComplete(response: FanshipCouponDistributeResponse) {
                if (response.coupon != null) {
                    // クーポン詳細画面を表示
                    handleOpenAction(couponUuid)
                }
            }

            // クーポンの配布に失敗した場合
            override fun onError(e: FanshipCouponErrorException) {}
        },
    )
}

/**
 * クーポン一覧を表示
 */
private fun showCouponListFragment() {
    val fragment = FanshipCouponListFragment()
    supportFragmentManager.beginTransaction()
        .replace(R.id.fanship_coupon_container_list, fragment)
        .setReorderingAllowed(true)
        .commit()
}

/**
 * クーポン詳細を表示
 * @param couponUuid クーポンの UUID
 */
private fun showCouponDetail(couponUuid: String?) {
    if (couponUuid != null) {
        val fragment = FanshipCouponDetailFragment()
        val bundle = Bundle()
        bundle.putString(FanshipCouponDetailFragment.COUPON_KEY, couponUuid)
        fragment.arguments = bundle
        supportFragmentManager.beginTransaction()
            .replace(R.id.fanship_coupon_container_detail, fragment)
            .setReorderingAllowed(true)
            .addToBackStack(null)
            .commit()
        }
    }
}
class LinkActivity extends AppCompatActivity {

private String userId = "";
private String URL_HOST = "jp.popinfo.coupon";
private String PARAM_ACTION = "action";
private String ACTION_OPEN = "open";
private String ACTION_DISTRIBUTE = "distribute";
private String ACTION_OPEN_ON_DISTRIBUTE = "openOnDistribution";
private int pageForFindDistributionId = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_link);

    userId = Popinfo.getUserId(this);
    showCouponListFragment();
    handleIntent(getIntent());
}

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    handleIntent(intent);
}

private void handleIntent(Intent intent) {

    // カスタム URL 経由で無い場合は処理を抜ける
    if (intent == null || !Intent.ACTION_VIEW.equals(intent.getAction())) {
        return;
    }

    // ULIを取得
    Uri uri = intent.getData();
    if (uri == null) {
        return;
    }

    // action指定が無い場合は処理を抜ける
    if (uri.getQueryParameter(PARAM_ACTION) == null) {
        return;
    }

    // クーポン配布用カスタム URL の判断
    String authority = uri.getAuthority();
    if (!authority.equals(URL_HOST)) {
        return;
    }

    // uuidが無い場合は処理を抜ける
    String uuid = uri.getQueryParameter("uuid");
    if (uuid == null) {
        return;
    }

    // Actionごとに処理を分離する
    String action = intent.getData().getQueryParameter(PARAM_ACTION);
    if (action.equals(ACTION_OPEN)) {
        // ①クーポン詳細を表示するサンプル(open)
        handleOpenAction(uuid);
    } else if (action.equals(ACTION_DISTRIBUTE)) {
        // ②クーポン配布を行い一覧画面へ遷移するサンプル(distribute)
        handleDistributeAction(uuid);
    } else if (action.equals(ACTION_OPEN_ON_DISTRIBUTE)) {
        // ③クーポン配布を行いクーポン詳細を表示するサンプル(openOnDistribution)
        handleOpenOnDistributionAction(uuid);
    }
}

/**
* ①クーポン詳細を表示するサンプル(open)
*/
private void handleOpenAction(String uuid) {
    // クーポン一覧を取得
    FanshipCouponClient.getCouponList(this,
            userId,
            FanshipCouponClient.SortEnum.USABLE_END_DATE,
            true,
            pageForFindDistributionId,
            null,
            new FanshipCouponAsyncCallback<FanshipCouponListResponse>() {
                // クーポン一覧の取得に成功した場合
                @Override
                public void onComplete(FanshipCouponListResponse couponResponse) {
                    String targetId = null;
                    boolean hasNextPage = !couponResponse.couponList.isEmpty();

                    // 対象のクーポンが一覧に含まれているかをForループで検索
                    for (int i = 0; i < couponResponse.couponList.size(); i++) {
                        FanshipCoupon coupon = couponResponse.couponList.get(i);

                        // UUIDが一致 かつ使用済みではない場合
                        if(coupon.uuid.startsWith(uuid) && !FanshipCouponUtils.isUsedCoupon(coupon)) {
                            // TargetIDとして取り出す
                            targetId = coupon.uuid;
                            break;
                        }
                    }

                    // TargetIDがNUllではない場合(上の処理で見つかった場合)
                    if(targetId != null) {
                        String finalTargetId = targetId;
                        runOnUiThread(() -> {
                            // クーポン詳細を表示
                            showCouponDetail(finalTargetId);
                            pageForFindDistributionId = 1;
                        });
                    // 次ページが存在している場合
                    } else if(hasNextPage) {
                        // ページ番号を加算し同じ処理を最初から繰り返す
                        pageForFindDistributionId++;
                        handleOpenAction(uuid);
                    } else {
                        // 次ページがページが存在しない場合は終了
                        finish();
                    }
                }

                // クーポン一覧の取得に失敗した場合
                @Override
                public void onError(FanshipCouponErrorException e) {
                }
            });

}

/**
* ②クーポン配布を行い一覧画面へ遷移するサンプル(distribute)
*/
private void handleDistributeAction(String couponUuid) {

    FanshipCouponClient.distributeCoupon(
            getApplicationContext(),
            Popinfo.getPopinfoId(getApplicationContext()),
            couponUuid,
            new FanshipCouponAsyncCallback<FanshipCouponDistributeResponse>() {
                // クーポンの配布に成功した場合
                @Override
                public void onComplete(FanshipCouponDistributeResponse response) {
                    // クーポン一覧画面へ遷移
                    if (response.coupon != null) {
                        Intent intent = new Intent(getApplicationContext(), FanshipCouponList.class);
                        intent.putExtra(FanshipCouponList.DISTRIBUTE_ID, response.coupon.uuid);
                        startActivity(intent);
                    }
                }

                // クーポンの配布に失敗した場合
                @Override
                public void onError(FanshipCouponErrorException e) {
                }
            });
}

/**
* ③クーポン配布を行いクーポン詳細を表示するサンプル(openOnDistribution)
*/
private void handleOpenOnDistributionAction(String couponUuid) {

    FanshipCouponClient.distributeCoupon(
            getApplicationContext(),
            Popinfo.getPopinfoId(getApplicationContext()),
            couponUuid,
            new FanshipCouponAsyncCallback<FanshipCouponDistributeResponse>() {
                // クーポン配布に成功した場合
                @Override
                public void onComplete(FanshipCouponDistributeResponse response) {
                    if (response.coupon != null) {
                        // クーポン詳細画面を表示
                        handleOpenAction(couponUuid);
                    }
                }

                // クーポンの配布に失敗した場合
                @Override
                public void onError(FanshipCouponErrorException e) {
                }
            });
}

/**
* クーポン一覧を表示
*/
private void showCouponListFragment() {
    FanshipCouponListFragment fragment = new FanshipCouponListFragment();
    getSupportFragmentManager().beginTransaction()
            .replace(R.id.fanship_coupon_container_list, fragment)
            .setReorderingAllowed(true)
            .commit();
}

/**
* クーポン詳細を表示
* @param couponUuid クーポンの UUID
*/
private void showCouponDetail(String couponUuid) {

    if (couponUuid != null) {
        FanshipCouponDetailFragment fragment = new FanshipCouponDetailFragment();
        Bundle bundle = new Bundle();
        bundle.putString(FanshipCouponDetailFragment.COUPON_KEY, couponUuid);
        fragment.setArguments(bundle);

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.fanship_coupon_container_detail, fragment)
                .setReorderingAllowed(true)
                .addToBackStack(null)
                .commit();
        }
    }
}

Memo

クーポン一覧画面へ遷移する際、クーポンの ID をパラメータとしてセットすることで一覧画面を表示した際に指定したクーポンの箇所へスクロールします。

※ fragment での遷移をする際は Bundle に FanshipCouponListFragment.COUPON_ID というキーにクーポン ID を含めることで、同様の挙動を行います。