PayPal’s New Android SDK:
Kicking Ass With Payments
Tim Messerschmidt
Droidcon Paris 2013
This talk will be about
-  What is PayPal?
-  Log In with PayPal
-  PayPal Android SDK
Who Am I?
Tim Messerschmidt,
Developer Evangelist
working for PayPal.
Android Developer
living in Berlin.
I ♥ Java, Ruby, CSS3,
HTML5 & JavaScript!
What is PayPal?
Enable
merchants to
sell online
What is PayPal?
Enable
customers to
buy online
What is PayPal?
Payment Scenario
Sender Receiver
Transaction
eCommerce
Sender Receiver
Transaction
Item /
Service
Secure
Easy
Fast
Requirements
128m
active users
What is PayPal?
193
countries & regions
What is PayPal?
25
supported currencies
What is PayPal?
80
localized websites
What is PayPal?
France
fully supported
What is PayPal?
Local Merchants
Big Mac Menu:
-  Fries
-  Ketchup
-  Water
... keeping it healthy
Painless Payments for Droids
Tim Messerschmidt
Identity
Login with...
Google Facebook Twitter
... or PayPal.
Login with...
Name
Email
Date of Birth
Locale
Time Zone
Address
Gender
Language
Phone Number
Verified Account
Creation Date
Your Identity
Log In via
PayPal in the
browser or a
WebView.
Log In with PayPal
Authorization &
Authentication
Log In with PayPal
OAuth 2.0 &
OpenID Connect
No need to (re-)enter
your password after
logging in
Seamless Checkout
Painless Payments for Droids
Tim Messerschmidt
Summarizing Identity
Painless Payments for Droids
Tim Messerschmidt
Money
Lots Of Money
Painless Payments for Droids
Tim Messerschmidt
Digital Goods
Physical Goods
Physical Goods
2 ways
Backend or via SDK
Using PayPal
Android SDK
Sample App:
•  Sell a football jersey
•  Fast Checkout
•  Nice Interface
Present the
product & allow
to purchase it
Android SDK
Allow to pay via
PayPal or Card
Android SDK
The user enters
his credentials:
•  Email
•  Password
Android SDK
The user needs
to confirm his
payment...
Android SDK
... and will be
presented a
confirmation of
his purchase
afterwards.
Android SDK
That’s nice... BUT:
What if the user
doesn’t want to use
PayPal or doesn’t
have an account?
Accept credit
cards in your
application
manually or...
Android SDK
... via image
recognition
technology in
your app!
Android SDK
Implementation
In 10 minutes
How-to
<!-- Hardware features -->
<uses-feature
android:name="android.hardware.camera”
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus”
android:required="false" />
<!–- Permissions -->
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.INTERNET" />
<!-- card.io scanning -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.VIBRATE" />
How-to
AndroidManifest.xml:
<!-- Hardware features -->
<uses-feature
android:name="android.hardware.camera”
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus”
android:required="false" />
<!–- Permissions -->
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.INTERNET" />
<!-- card.io scanning -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.VIBRATE" />
How-to
AndroidManifest.xml:
<!-- Hardware features -->
<uses-feature
android:name="android.hardware.camera”
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus”
android:required="false" />
<!–- Permissions -->
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.INTERNET" />
<!-- card.io scanning -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.VIBRATE" />
How-to
AndroidManifest.xml:
<!-- Hardware features -->
<uses-feature
android:name="android.hardware.camera”
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus”
android:required="false" />
<!–- Permissions -->
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission
android:name="android.permission.INTERNET" />
<!-- card.io scanning -->
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission
android:name="android.permission.VIBRATE" />
How-to
AndroidManifest.xml:
<service
android:name="com.paypal.android.sdk.payments.PayPalService"
android:exported="false"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.LoginActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentMethodActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentConfirmActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentCompletedActivity"/>
<activity
android:name="io.card.payment.CardIOActivity"
android:configChanges="keyboardHidden|orientation"/>
<activity
android:name="io.card.payment.DataEntryActivity"/>
How-to
AndroidManifest.xml:
<service
android:name="com.paypal.android.sdk.payments.PayPalService"
android:exported="false"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.LoginActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentMethodActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentConfirmActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentCompletedActivity"/>
<activity
android:name="io.card.payment.CardIOActivity"
android:configChanges="keyboardHidden|orientation"/>
<activity
android:name="io.card.payment.DataEntryActivity"/>
How-to
AndroidManifest.xml:
<service
android:name="com.paypal.android.sdk.payments.PayPalService"
android:exported="false"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.LoginActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentMethodActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentConfirmActivity"/>
<activity
android:name="com.paypal.android.sdk.payments.PaymentCompletedActivity"/>
<activity
android:name="io.card.payment.CardIOActivity"
android:configChanges="keyboardHidden|orientation"/>
<activity
android:name="io.card.payment.DataEntryActivity"/>
How-to
AndroidManifest.xml:
// Can be NO_NETWORK for OFFLINE, SANDBOX for TESTING and LIVE for PRODUCTION
private static final String CONFIG_ENVIRONMENT =
PaymentActivity.ENVIRONMENT_NO_NETWORK;
// note that these credentials will differ between live & sandbox environments.
private static final String CONFIG_CLIENT_ID =
"credential from developer.paypal.com";
// when testing in sandbox, this is likely the -facilitator email address.
private static final String CONFIG_RECEIVER_EMAIL =
"your@email.com";
How-to
Your Activity:
Define your credentials and Environment first.
// Can be NO_NETWORK for OFFLINE, SANDBOX for TESTING and LIVE for PRODUCTION
private static final String CONFIG_ENVIRONMENT =
PaymentActivity.ENVIRONMENT_NO_NETWORK;
// note that these credentials will differ between live & sandbox environments.
private static final String CONFIG_CLIENT_ID =
"credential from developer.paypal.com";
// when testing in sandbox, this is likely the -facilitator email address.
private static final String CONFIG_RECEIVER_EMAIL =
"your@email.com";
How-to
Your Activity:
Define your credentials and Environment first.
// Can be NO_NETWORK for OFFLINE, SANDBOX for TESTING and LIVE for PRODUCTION
private static final String CONFIG_ENVIRONMENT =
PaymentActivity.ENVIRONMENT_NO_NETWORK;
// note that these credentials will differ between live & sandbox environments.
private static final String CONFIG_CLIENT_ID =
"credential from developer.paypal.com";
// when testing in sandbox, this is likely the -facilitator email address.
private static final String CONFIG_RECEIVER_EMAIL =
"your@email.com";
How-to
Your Activity:
Define your credentials and Environment first.
// Can be NO_NETWORK for OFFLINE, SANDBOX for TESTING and LIVE for PRODUCTION
private static final String CONFIG_ENVIRONMENT =
PaymentActivity.ENVIRONMENT_NO_NETWORK;
// note that these credentials will differ between live & sandbox environments.
private static final String CONFIG_CLIENT_ID =
"credential from developer.paypal.com";
// when testing in sandbox, this is likely the -facilitator email address.
private static final String CONFIG_RECEIVER_EMAIL =
"your@email.com";
How-to
Your Activity:
Define your credentials and Environment first.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// your code here
Intent intent = new Intent(this, PayPalService.class);
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startService(intent);
}
How-to
Your Activity:
Start the PayPal-Service in your onCreate( ) method
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// your code here
Intent intent = new Intent(this, PayPalService.class);
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startService(intent);
}
How-to
Your Activity:
Start the PayPal-Service in your onCreate( ) method
PayPalPayment thingToBuy =
new PayPalPayment(new BigDecimal(“59.99"), "USD", "Paris SG Jersey");
Intent intent = new Intent(this, PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
intent.putExtra(PaymentActivity.EXTRA_PAYER_ID, "myPayer");
// Repeat passing the credentials
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startActivityForResult(intent, PAYMENT_REQUEST);
How-to
Your Activity:
Start the payment itself via a button or something similar
PayPalPayment thingToBuy =
new PayPalPayment(new BigDecimal(“59.99"), "USD", "Paris SG Jersey");
Intent intent = new Intent(this, PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
intent.putExtra(PaymentActivity.EXTRA_PAYER_ID, "myPayer");
// Repeat passing the credentials
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startActivityForResult(intent, PAYMENT_REQUEST);
How-to
Your Activity:
Start the payment itself via a button or something similar
PayPalPayment thingToBuy =
new PayPalPayment(new BigDecimal(“59.99"), "USD", "Paris SG Jersey");
Intent intent = new Intent(this, PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
intent.putExtra(PaymentActivity.EXTRA_PAYER_ID, "myPayer");
// Repeat passing the credentials
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startActivityForResult(intent, PAYMENT_REQUEST);
How-to
Your Activity:
Start the payment itself via a button or something similar
PayPalPayment thingToBuy =
new PayPalPayment(new BigDecimal(“59.99"), "USD", "Paris SG Jersey");
Intent intent = new Intent(this, PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
intent.putExtra(PaymentActivity.EXTRA_PAYER_ID, "myPayer");
// Repeat passing the credentials
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startActivityForResult(intent, PAYMENT_REQUEST);
How-to
Your Activity:
Start the payment itself via a button or something similar
PayPalPayment thingToBuy =
new PayPalPayment(new BigDecimal(“59.99"), "USD", "Paris SG Jersey");
Intent intent = new Intent(this, PaymentActivity.class);
intent.putExtra(PaymentActivity.EXTRA_PAYMENT, thingToBuy);
intent.putExtra(PaymentActivity.EXTRA_PAYER_ID, "myPayer");
// Repeat passing the credentials
intent.putExtra(PaymentActivity.EXTRA_PAYPAL_ENVIRONMENT, CONFIG_ENVIRONMENT);
intent.putExtra(PaymentActivity.EXTRA_CLIENT_ID, CONFIG_CLIENT_ID);
intent.putExtra(PaymentActivity.EXTRA_RECEIVER_EMAIL, CONFIG_RECEIVER_EMAIL);
startActivityForResult(intent, PAYMENT_REQUEST);
How-to
Your Activity:
Start the payment itself via a button or something similar
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm =
data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
if (confirm != null) {
verifyPayment(confirm);
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// Show the user that this got canceled
} else if (resultCode == PaymentActivity.RESULT_PAYMENT_INVALID) {
// Check the docs ;)
}
}
How-to
Your Activity:
Check the result after the user used PayPal
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm =
data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
if (confirm != null) {
verifyPayment(confirm);
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// Show the user that this got canceled
} else if (resultCode == PaymentActivity.RESULT_PAYMENT_INVALID) {
// Check the docs ;)
}
}
How-to
Your Activity:
Check the result after the user used PayPal
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm =
data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
if (confirm != null) {
verifyPayment(confirm);
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// Show the user that this got canceled
} else if (resultCode == PaymentActivity.RESULT_PAYMENT_INVALID) {
// Check the docs ;)
}
}
How-to
Your Activity:
Check the result after the user used PayPal
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
PaymentConfirmation confirm =
data.getParcelableExtra(PaymentActivity.EXTRA_RESULT_CONFIRMATION);
if (confirm != null) {
verifyPayment(confirm);
}
} else if (resultCode == Activity.RESULT_CANCELED) {
// Show the user that this got canceled
} else if (resultCode == PaymentActivity.RESULT_PAYMENT_INVALID) {
// Check the docs ;)
}
}
How-to
Your Activity:
Check the result after the user used PayPal
@Override
public void onDestroy() {
stopService(new Intent(this, PayPalService.class));
super.onDestroy();
}
How-to
Your Activity:
Stop your service in the lifecycle’s onDestroy( ) method to make sure it ends nicely
and doesn’t use unneeded resources.
Your app needs to
communicate with
a server to verify
payments
Verifying Payments
Criteria to use to
verify payments:
bit.ly/19FIis6
Verifying Payments
{
"proof_of_payment": {
"rest_api": {
"state": "approved",
"payment_id": "API-PAYMENT-ID-1843"
}
},
"payment": {
"short_description": "Paris SG Jersey",
"amount": ”59.99",
"currency_code": "USD"
},
"client": {
"platform": "Android",
"paypal_sdk_version": "1.0.2",
"environment": "live",
"product_name": "PayPal Android SDK"
}
}
Verifying Payments
REST-API proof of payment: Adaptive Payments proof of payment:
{
"proof_of_payment": {
"adaptive_payment": {
"pay_key": "AP-70M68096ML426802W",
"payment_exec_status": "COMPLETED",
"timestamp": "2013-02-20T00:26:25Z",
"app_id": "APP-91B933855X481767M"
}
},
"payment": {
"short_description": "Paris SG Shirt",
"amount": "59.99",
"currency_code": "USD"
},
"client": {
"platform": "Android",
"paypal_sdk_version": "1.0.2",
"environment": "live",
"product_name": "PayPal Android SDK"
}
}
{
"proof_of_payment": {
"rest_api": {
"state": "approved",
"payment_id": "API-PAYMENT-ID-1843"
}
},
"payment": {
"short_description": "Paris SG Jersey",
"amount": ”59.99",
"currency_code": "USD"
},
"client": {
"platform": "Android",
"paypal_sdk_version": "1.0.2",
"environment": "live",
"product_name": "PayPal Android SDK"
}
}
Verifying Payments
REST-API proof of payment: Adaptive Payments proof of payment:
{
"proof_of_payment": {
"adaptive_payment": {
"pay_key": "AP-70M68096ML426802W",
"payment_exec_status": "COMPLETED",
"timestamp": "2013-02-20T00:26:25Z",
"app_id": "APP-91B933855X481767M"
}
},
"payment": {
"short_description": "Paris SG Shirt",
"amount": "59.99",
"currency_code": "USD"
},
"client": {
"platform": "Android",
"paypal_sdk_version": "1.0.2",
"environment": "live",
"product_name": "PayPal Android SDK"
}
}
Somebody did that
work for you:
bit.ly/19FHQde
Verifying Payments
Android Studio
Gradle doesn’t
support
bundling .so
files with your
apk yet
US only
Europe coming soon!
Important
Documentation
developer.paypal.com
Information
Open Source
GitHub.com/paypal
Information
Questions?
Thanks!
Tim Messerschmidt
@SeraAndroid
tmesserschmidt@paypal.com
SlideShare.com/paypal

Droidcon Paris: The new Android SDK