カスタム 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 を含めることで、同様の挙動を行います。