androidmercadopago

Android Studio: Transparent checkout using Mercado Pago


I am trying to implement for the first time the Mercado Pago's transparent checkout in Android.

I've already downloaded the newest version of the SDK provided in https://github.com/mercadopago/px-android and executed it normally in the Emulator.

In the GitHub page mentioned above, we have an explanation of how to implement Mercado Pago's checkout with just one line of code:

new MercadoPagoCheckout.Builder("public_key", "checkout_preference_id")
    .build()
    .startPayment(activityOrContext, requestCode);

Where public_key we can get in the credentials webpage. But the String checkout_preference_id I have no idea of how to create it, even though they showed how to create it at the end of the GitHub webpage.

Create your preference id

curl -X POST \
     'https://api.mercadopago.com/checkout/preferences?access_token=ACCESS_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{
           "items": [
               {
               "title": "Dummy Item",
               "description": "Multicolor Item",
               "quantity": 1,
               "currency_id": "ARS",
               "unit_price": 10.0
               }
           ],
           "payer": {
               "email": "payer@email.com"
           }
     }'

I tried to put a random String in checkout_preference_id, but it did not work. Only the String in the example app of Mercado Pago worked.

private static final String DUMMY_PREFERENCE_ID = "243962506-0bb62e22-5c7b-425e-a0a6-c22d0f4758a9";

All the other ways of implementing it presented in the example app of Mercado Pago require a fake confirmation of payment.

I appreciate if anyone could show some code of how to create and pass the variable checkout_preference_id into the main command of Mercado Pago payment.

EDIT

I also appreciate if anyone could give us an example of a Not fake confirmation of payment with some code.

I guess checkout_preference_id can be accessed via a Marketplace website or maybe creating a curl using Android's webservice. Then, it is still a mystery to me.

Concerning to the alternitive way of paying with MercadoPago, we have this other arguments to pass:

new MercadoPagoCheckout.Builder("public_key", checkoutPreference, paymentConfiguration)
                .build()
                .startPayment(activityOrContext, requestCode);

Where checkoutPreference allows you to create a custom item to sell.

final Item item = new Item.Builder("Product Title", 1, new BigDecimal(12.3)).setDescription("Product Description").build();
CheckoutPreference checkoutPreference = new CheckoutPreference.Builder(Sites.BRASIL, "a@a.a", Collections.singletonList(item)).setDefaultInstallments(1).build();

paymentConfiguration is implemented the fake confirmation of payment.

PaymentConfiguration paymentConfiguration = new PaymentConfiguration.Builder(new MyPaymentProcessor()).build();

Where the class MyPaymentProcessor() and the other classes in which it depends on can be found in the GitHub example.


Solution

  • Álysson Alexandre helped to understand how to generate the String checkout_preference_id.

    Below you will see the minimum code needed to receive a payment with MercadoPago.

    Firstly, you have to add the dependencies in the build.gradle (Module: app)

    // Dealing with HTTP internet connection
    implementation 'com.android.volley:volley:1.1.1'
    
    //Dealing with MercadoPago SDK and dependencies
    implementation 'com.mercadopago.android.px:checkout:4.0.+'
    

    Some people recommend to add internet permission in the Manifest

    <uses-permission android:name="android.permission.INTERNET" />
    

    Next, you need to create a JSONObject and there are different ways of doing that.

    This way:

        StringBuilder strjsonobj = new StringBuilder();
        String strJson = "{\n" +
                "           \"items\": [\n" +
                "               {\n" +
                "               \"title\": \"Item\",\n" +
                "               \"description\": \"Multicolor Item\",\n" +
                "               \"quantity\": 1,\n" +
                "               \"currency_id\": \"BRL\",\n" +
                "               \"unit_price\": 35.0\n" +
                "               }\n" +
                "           ],\n" +
                "           \"payer\": {\n" +
                "\t\t    \"name\": \"Núbia\",\n" +
                "\t\t    \"surname\": \"Macedo\",\n" +
                "\t\t    \"email\": \"leann@gmail.com\",\n" +
                "\t\t    \"date_created\": \"2015-06-02T12:58:41.425-04:00\",\n" +
                "\t\t    \"phone\": {\n" +
                "\t\t      \"area_code\": \"\",\n" +
                "\t\t      \"number\": \"880.402.7555\"\n" +
                "\t\t    },\n" +
                "\t\t    \"identification\": {\n" +
                "\t\t      \"type\": \"DNI\",\n" +
                "\t\t      \"number\": \"123456789\"\n" +
                "\t\t    },\n" +
                "\t\t    \"address\": {\n" +
                "\t\t      \"street_name\": \"Núbia Viela\",\n" +
                "\t\t      \"street_number\": 25598,\n" +
                "\t\t      \"zip_code\": \"8972\"\n" +
                "\t\t    }\n" +
                "\t\t  }\n" +
                "     }";
    
        strjsonobj.append(strJson);
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject = new JSONObject(strjsonobj.toString());
            Log.i("debinf MainAct", "object is : "+jsonObject);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    

    Or this way:

        JSONObject jsonObject = new JSONObject();
        final JSONObject itemJSON = new JSONObject();
        final JSONObject payerJSON = new JSONObject();
        JSONArray itemJsonArray = new JSONArray();
        try {
    
            itemJSON.put("title", "Dummy Item");
            itemJSON.put("description", "Multicolor Item");
            itemJSON.put("quantity", 1);
            itemJSON.put("currency_id", "BRL");
            itemJSON.put("unit_price", 2.10);
    
            itemJsonArray.put(itemJSON);
    
            JSONObject phoneJSON = new JSONObject();
            phoneJSON.put("area_code", "");
            phoneJSON.put("number", "880.402.7555");
            JSONObject idJSON = new JSONObject();
            idJSON.put("type", "DNI");
            idJSON.put("number", "123456789");
            JSONObject addressJSON = new JSONObject();
            addressJSON.put("street_name", "Núbia Viela");
            addressJSON.put("street_number", 25598);
            addressJSON.put("zip_code", "8972");
    
            payerJSON.put("name", "Núbia");
            payerJSON.put("surname", "Macedo");
            payerJSON.put("email", "leann@gmail.com");
            payerJSON.put("date_created", "2015-06-02T12:58:41.425-04:00");
            payerJSON.put("phone", phoneJSON);
            payerJSON.put("identification", idJSON);
            payerJSON.put("address", addressJSON);
    
    
            jsonObject.put("items", itemJsonArray);
            jsonObject.put("payer", payerJSON);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    

    MercadoPago suggests to send as much information as you can about the payer in order to increase the rate of payment conversion. But you can send as little as shown in the question.

    Besides that, you can personalize other things in the JSONObject such as shown here

    Now, let's create the variable String checkout_preference_id. For that, I used the method volley. When the MercadoPago server sends back our variable, we will automatically start the payment.

        RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
        final String url = "https://api.mercadopago.com/checkout/preferences?access_token="+ACCESS_TOKEN_SANDBOX;
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                try {
                    Log.i("debinf MainAct", "response JSONObject: "+response);
                    String checkoutPreferenceId = response.getString("id");
                    new MercadoPagoCheckout.Builder(PUBLIC_KEY_SANDBOX, checkoutPreferenceId).build().startPayment(MainActivity.this,REQUEST_CODE);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.i("debinf MainAct", "response ERROR: "+error.networkResponse.allHeaders);
            }
        }){
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> headers = new HashMap<>();
                headers.put("Content-Type", "application/json");
                return headers;
            }
        };
        requestQueue.add(jsonObjectRequest);
    

    Use REQUEST_CODE sent by startPayment to obtain the checkout result in onActivityResult.

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        if (requestCode == REQUEST_CODE) {
            if (resultCode == MercadoPagoCheckout.PAYMENT_RESULT_CODE) {
                final Payment payment = (Payment) data.getSerializableExtra(MercadoPagoCheckout.EXTRA_PAYMENT_RESULT);
                ((TextView) findViewById(R.id.mp_results)).setText("Resultado del pago: " + payment.getStatus());
                //Done!
            } else if (resultCode == RESULT_CANCELED) {
                if (data != null && data.getExtras() != null
                    && data.getExtras().containsKey(MercadoPagoCheckout.EXTRA_ERROR)) {
                    final MercadoPagoError mercadoPagoError =
                        (MercadoPagoError) data.getSerializableExtra(MercadoPagoCheckout.EXTRA_ERROR);
                    ((TextView) findViewById(R.id.mp_results)).setText("Error: " +  mercadoPagoError.getMessage());
                    //Resolve error in checkout
                } else {
                    //Resolve canceled checkout
                }
            }
        }
    }
    

    That's it! Please, be free to improve the above code. Mainly, regarding to the security issues.