droidcon paris: the new android sdk
DESCRIPTION
This speech was held by Tim Messerschmidt at Droidcon Paris 2013.TRANSCRIPT
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 ... !""#$%& $' (")*'(+
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 =
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 =
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 =
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 =
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?