Notify users of Alipay+ availability
When a user travels abroad, the Mobile Payment Provider (MPP) can proactively notify the user of Alipay+ availability if you (the MPP) detect that the user is abroad and Alipay+ is available in the user's region.
This topic introduces how to check Alipay+ availability and send notifications when Alipay+ is available.
Workflow
The following figure illustrates the workflow of the periodic task which is to check whether the user is abroad in a location where Alipay+ is available and send notifications to users of Alipay+ availability.
Figure 1: Notify users of Alipay+ availability
- The MPP app starts the periodic task by calling the startMonitor API. See Sample code for more information. (Step 1)
- The MPP app checks whether the number of attempts to check Alipay+ availability exceeds the daily limit. The MPP can set the maximum limit for a natural day. (Step 2)
- (Optional) If the attempt is within the maximum number of attempts, the MPP app can obtain the user's location based on its own processing logic or calls the getCurrentRegion API from Alipay+ Client SDK to obtain the user's location. (Steps 3-5)
- If the attempt is within the maximum number of attempts, the MPP app calls the isAlipayplusSupportedRegion API to check whether Alipay+ is available in the user's current location. (Steps 6-7)
- The registered listener in the startMonitor API notifies the MPP app when the user is abroad and in a region where the Alipay+ is available. Then, the MPP app decides the notification method, such as in-app notification or SMS message, and the frequency for notifying the user of Alipay+ availability. (Steps 8-9)
Sample code
Android sample code
iOS sample code
copy
public interface IAlipayPlusRegionListener {
void didEnterSupportedAlipayPlusRegion();
}
copy
public class AlipayPlusRegionHelper {
private static volatile AlipayPlusRegionHelper instance;
private final long crossBorderDetectedRefreshTime = 2 * 60 * 60 * 1000;
private final int maxDetectedCount = 10;
private Handler crossingBorderDetectHandler;
private IAlipayPlusRegionListener listener;
private boolean hasStartMonitor = false;
public final String KEY_CURRENT_DETECTED_COUNT = "currentDetectedCount";
public final String KEY_LAST_DETECTED_TIME = "lastDetectedTime";
private final String MCC_STORAGE_NAME = "mccAlipayPlus";
public static AlipayPlusRegionHelper getInstance() {
if (instance == null) {
synchronized (AlipayPlusRegionHelper.class) {
if (instance == null) {
instance = new AlipayPlusRegionHelper();
}
}
}
return instance;
}
/**
* start monitoring whether A+ is available and then notifying
*
* @param listener IAlipayPlusRegionListener
*/
public synchronized void startMonitor(Context context, IAlipayPlusRegionListener listener) {
if (hasStartMonitor) {
return;
}
hasStartMonitor = true;
this.listener = listener;
if (crossingBorderDetectHandler == null) {
HandlerThread thread = new HandlerThread("AlipayPlus-CrossingBorderDetected-Thread");
thread.start();
crossingBorderDetectHandler = new Handler(thread.getLooper());
}
//delay 6s ensuring getting latest regionRule
scheduleNextDetectedTask(context, 6 * 1000);
}
/**
* stop monitoring whether A+ is available and then notifying
*/
public void stopMonitor() {
hasStartMonitor = false;
listener = null;
if (crossingBorderDetectHandler != null) {
crossingBorderDetectHandler.removeCallbacksAndMessages(null);
crossingBorderDetectHandler = null;
}
}
private void scheduleNextDetectedTask(Context context, long delayTimeMs) {
if (context == null) {
return;
}
crossingBorderDetectHandler.postDelayed(() -> {
long lastRefreshTime = getLong(context, KEY_LAST_DETECTED_TIME, 0);
long currentTime = System.currentTimeMillis();
boolean isSameDay = isSameDate(lastRefreshTime, currentTime);
if (!isSameDay) {
putInt(context, KEY_CURRENT_DETECTED_COUNT, 0);
}
int currentMaxCount = getInt(context, KEY_CURRENT_DETECTED_COUNT, 0);
if (currentMaxCount < maxDetectedCount) {
currentMaxCount++;
putInt(context, KEY_CURRENT_DETECTED_COUNT, currentMaxCount);
putLong(context, KEY_LAST_DETECTED_TIME, System.currentTimeMillis());
String region = AlipayPlusClient.getInstance().getCurrentRegion(context);
boolean isAvailable = AlipayPlusClient.getInstance().isAlipayPlusSupportedRegion(context, region);
if (isAvailable) {
//notify bizPart crossing border and A+ supported
if (listener != null) {
//back to main thread
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(() -> listener.didEnterSupportedAlipayPlusRegion());
}
}
}
//prepare next task
scheduleNextDetectedTask(context, crossBorderDetectedRefreshTime);
}, delayTimeMs);
}
private boolean isSameDate(long time1, long time2) {
boolean result = false;
try {
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
@SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dataStr1 = df.format(time1);
String dataStr2 = df.format(time2);
java.util.Date date1 = df.parse(dataStr1);
java.util.Date date2 = df.parse(dataStr2);
if (date1 != null && date2 != null) {
calendar1.setTime(date1);
calendar2.setTime(date2);
result = (calendar1.get(Calendar.ERA) == calendar2.get(Calendar.ERA)) && (calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR)) && (calendar1.get(Calendar.DAY_OF_YEAR) == calendar2.get(Calendar.DAY_OF_YEAR));
}
} catch (Exception ignored) {
}
return result;
}
private void putLong(Context context, String key, long value) {
context.getSharedPreferences(MCC_STORAGE_NAME, Context.MODE_PRIVATE).edit().putLong(key, value).apply();
}
private Long getLong(Context context, String key, long defaultValue) {
return context.getSharedPreferences(MCC_STORAGE_NAME, Context.MODE_PRIVATE).getLong(key, defaultValue);
}
private void putInt(Context context, String key, int value) {
context.getSharedPreferences(MCC_STORAGE_NAME, Context.MODE_PRIVATE).edit().putInt(key, value).apply();
}
private int getInt(Context context, String key, int defaultValue) {
return context.getSharedPreferences(MCC_STORAGE_NAME, Context.MODE_PRIVATE).getInt(key, defaultValue);
}
}