Alipay+ DocsAlipay+ Docs

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.


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

  1. The MPP app starts the periodic task by calling the startMonitor API. See Sample code for more information. (Step 1)
  2. 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)
  3. (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)
  4. 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)
  5. 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

public interface IAlipayPlusRegionListener {
    void didEnterSupportedAlipayPlusRegion();
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) {
        hasStartMonitor = true;

        this.listener = listener;
        if (crossingBorderDetectHandler == null) {
            HandlerThread thread = new HandlerThread("AlipayPlus-CrossingBorderDetected-Thread");
            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 = null;

    private void scheduleNextDetectedTask(Context context, long delayTimeMs) {
        if (context == null) {

        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) {
                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());
       -> 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) {

                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);