PayPal
Mobiele toekomstige betalingen (end-to-end-app)
Zoeken…
Opmerkingen
Dit voorbeeld toont een praktisch voorbeeld van het creëren van een toekomstige PayPal-betaling vanaf een Android-apparaat met behulp van een Node-server.
Android Stap 1: Lay-out, initialisatie en reactie van de server
De volledige voorbeeldcode voor deze applicatie (Android + Node-server) is beschikbaar in de PayPal Developer Github-repository .
De eerste fase van het maken van het Android-gedeelte van onze applicatie is het instellen van een basislay-out en het omgaan met reacties die terugkomen van de server die we in Node instellen.
Begin met het maken van een nieuw PayPal-configuratieobject om uw toepassingsinformatie te bewaren.
private static PayPalConfiguration config = new PayPalConfiguration()
.environment(PayPalConfiguration.ENVIRONMENT_SANDBOX)
.clientId("YOUR APPLICATION CLIENT ID")
.merchantName("My Store")
.merchantPrivacyPolicyUri(Uri.parse("https://www.example.com/privacy"))
.merchantUserAgreementUri(Uri.parse("https://www.example.com/legal"));
Vervolgens voegen we een eenvoudige knop toe aan onCreate(...) om op te treden als onze betalingsinitiatie. Dit is gewoon om de actie te activeren en moet worden geplaatst als het initiatieproces voor het creëren van een toekomstige betaling voor een gebruiker (bijvoorbeeld wanneer zij een abonnement overeenkomen).
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.paypal_button);
}
Onder res > layout > activity_main.xml voegen we de definitie voor de knop met de bijbehorende actie toe, wanneer erop wordt geklikt, wordt beginFuturePayment(...) , die we zo zullen definiëren.
<Button android:id="@+id/paypal_button"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:text="@string/paypal_button"
android:onClick="beginFuturePayment" />
Onder res > values > strings.xml voegen we vervolgens een tekenreeksreferentie toe voor de knop.
<string name="paypal_button">Process Future Payment</string>
Nu voegen we de knophandler toe om het gesprek te starten om het toekomstige betalingsproces te starten wanneer de gebruiker op de knop klikt. Wat we hier doen, is de betalingsservice starten met het configuratieobject dat we bovenaan dit voorbeeld hebben ingesteld.
public void beginFuturePayment(View view){
Intent serviceConfig = new Intent(this, PayPalService.class);
serviceConfig.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
startService(serviceConfig);
Intent intent = new Intent(this, PayPalFuturePaymentActivity.class);
intent.putExtra(PayPalService.EXTRA_PAYPAL_CONFIGURATION, config);
startActivityForResult(intent, 0);
}
Wanneer die oproep tot het doen van een toekomstige betaling wordt geïnitieerd, zullen we wat informatie ontvangen die naar onze server moet worden verzonden. We halen deze informatie uit het geldige toekomstige betalingsverzoek ( authCode en metadataId ) en voeren vervolgens het async-verzoek uit naar de server om de toekomstige betaling te voltooien (gedetailleerd in stap 2).
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
if (resultCode == Activity.RESULT_OK){
PayPalAuthorization auth = data.getParcelableExtra(PayPalFuturePaymentActivity.EXTRA_RESULT_AUTHORIZATION);
if (auth != null){
try{
//prepare params to be sent to server
String authCode = auth.getAuthorizationCode();
String metadataId = PayPalConfiguration.getClientMetadataId(this);
String [] params = {authCode, metadataId};
//process async server request for token + payment
ServerRequest req = new ServerRequest();
req.execute(params);
} catch (JSONException e) {
Log.e("FPSample", "JSON Exception: ", e);
}
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Log.i("FPSample", "User canceled.");
} else if (resultCode == PayPalFuturePaymentActivity.RESULT_EXTRAS_INVALID) {
Log.i("FPSample", "Invalid configuration");
}
}
Ten slotte definiëren we onze onDestroy() .
@Override
public void onDestroy(){
stopService(new Intent(this, PayPalService.class));
super.onDestroy();
}
Android Stap 2: Async-serververzoek
De volledige voorbeeldcode voor deze applicatie (Android + Node-server) is beschikbaar in de PayPal Developer Github-repository .
Op dit moment is op de PayPal-knop voor toekomstige betalingen geklikt, hebben we een authenticatiecode en metadata-ID van de PayPal SDK en moeten we deze doorgeven aan onze server om het toekomstige betalingsproces te voltooien.
In het onderstaande achtergrondproces doen we een paar dingen:
- We hebben de URI ingesteld die voor onze server
http://10.0.2.2:3000/fpstore, die het/fpstoreeindpunt raakt van onze server die op localhost draait. - Het JSON-object dat wordt doorgestuurd, wordt vervolgens ingesteld, dat de autorisatiecode en de metagegevens-ID bevat.
- De verbinding wordt vervolgens gemaakt. In het geval van een succesvol verzoek (bereik 200/201) kunnen we een reactie van de server verwachten. We lezen dat antwoord en geven het dan terug.
- Ten slotte hebben we een
onPostExecute(...)-methode ingesteld om die geretourneerde serverstring af te handelen. In het geval van dit voorbeeld is het gewoon vastgelegd.
public class ServerRequest extends AsyncTask<String, Void, String> {
protected String doInBackground(String[] params){
HttpURLConnection connection = null;
try{
//set connection to connect to /fpstore on localhost
URL u = new URL("http://10.0.2.2:3000/fpstore");
connection = (HttpURLConnection) u.openConnection();
connection.setRequestMethod("POST");
//set configuration details
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setAllowUserInteraction(false);
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
//set server post data needed for obtaining access token
String json = "{\"code\": \"" + params[0] + "\", \"metadataId\": \"" + params[1] + "\"}";
Log.i("JSON string", json);
//set content length and config details
connection.setRequestProperty("Content-length", json.getBytes().length + "");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
//send json as request body
OutputStream outputStream = connection.getOutputStream();
outputStream.write(json.getBytes("UTF-8"));
outputStream.close();
//connect to server
connection.connect();
//look for 200/201 status code for received data from server
int status = connection.getResponseCode();
switch (status){
case 200:
case 201:
//read in results sent from the server
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null){
sb.append(line + "\n");
}
bufferedReader.close();
//return received string
return sb.toString();
}
} catch (MalformedURLException ex) {
Log.e("HTTP Client Error", ex.toString());
} catch (IOException ex) {
Log.e("HTTP Client Error", ex.toString());
} catch (Exception ex) {
Log.e("HTTP Client Error", ex.toString());
} finally {
if (connection != null) {
try{
connection.disconnect();
} catch (Exception ex) {
Log.e("HTTP Client Error", ex.toString());
}
}
}
return null;
}
protected void onPostExecute(String message){
//log values sent from the server - processed payment
Log.i("HTTP Client", "Received Return: " + message);
}
}
Android Stap 3: knooppuntserver om toegangstoken te krijgen en betaling te verwerken
De volledige voorbeeldcode voor deze applicatie (Android + Node-server) is beschikbaar in de PayPal Developer Github-repository .
Vanaf stap 2 is een async-verzoek ingediend bij onze server op het /fpstore eindpunt, waarbij de authenticatiecode en de metadata-ID worden doorgegeven. We moeten deze nu inwisselen voor een token om het verzoek te voltooien en de toekomstige betaling te verwerken.
Eerst stellen we onze configuratievariabelen en -objecten in.
var bodyParser = require('body-parser'),
http = require('http'),
paypal = require('paypal-rest-sdk'),
app = require('express')();
var client_id = 'YOUR APPLICATION CLIENT ID';
var secret = 'YOUR APPLICATION SECRET';
paypal.configure({
'mode': 'sandbox',
'client_id': client_id,
'client_secret': secret
});
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
Nu stellen we een Express-route in die luistert naar POST-aanvragen die vanuit onze Android-code naar het /fpstore eindpunt zijn verzonden.
We doen een aantal dingen op deze route:
- We vangen de auth-code en metadata-ID van de POST-instantie.
- Vervolgens doen we een verzoek om
generateToken()tegenerateToken(), waarbij we het code-object passeren. Als dit lukt, krijgen we een token dat kan worden gebruikt om de betaling te maken. - Vervolgens worden de configuratieobjecten gemaakt voor de toekomstige betaling die moet worden uitgevoerd en wordt een verzoek tot
payment.create(...)gedaan, waarbij de toekomstige configuratie- en betalingsconfiguratieobjecten worden doorgegeven. Dit creëert de toekomstige betaling.
app.post('/fpstore', function(req, res){
var code = {'authorization_code': req.body.code};
var metadata_id = req.body.metadataId;
//generate token from provided code
paypal.generateToken(code, function (error, refresh_token) {
if (error) {
console.log(error);
console.log(error.response);
} else {
//create future payments config
var fp_config = {'client_metadata_id': metadata_id, 'refresh_token': refresh_token};
//payment details
var payment_config = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"transactions": [{
"amount": {
"currency": "USD",
"total": "3.50"
},
"description": "Mesozoic era monster toy"
}]
};
//process future payment
paypal.payment.create(payment_config, fp_config, function (error, payment) {
if (error) {
console.log(error.response);
throw error;
} else {
console.log("Create Payment Response");
console.log(payment);
//send payment object back to mobile
res.send(JSON.stringify(payment));
}
});
}
});
});
Ten slotte maken we de server aan om te luisteren op poort 3000.
//create server
http.createServer(app).listen(3000, function () {
console.log('Server started: Listening on port 3000');
});