PayPal WebView in Flutter doesnt work on Physical Device
711
PayPal doesn't support 'WebViews'. Only Chrome Custom Tabs (Android) or Safari View Controllers (iOS), which have an address bar. Ref: https://developer.paypal.com/docs/api/info-security-guidelines/#secure-applications
Also you are using the original REST v1/payments API, which will still work but is deprecated. The current PayPal Checkout API is v2/checkout/orders, documented here.
Author by
Emanuel Developer
Updated on December 27, 2022Comments
-
Emanuel Developer over 1 year
I have built a function to give my users the ability to pay with PayPal:
class PaypalServicesService { String domain = "https://api.sandbox.paypal.com"; // for sandbox mode //String domain = "https://api.paypal.com"; // for production mode // change clientId and secret with your own, provided by paypal String clientId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; String secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // for getting the access token from Paypal Future<String> getAccessToken() async { try { var client = BasicAuthClient(clientId, secret); var response = await client.post('$domain/v1/oauth2/token?grant_type=client_credentials'); if (response.statusCode == 200) { final body = convert.jsonDecode(response.body); return body["access_token"]; } return null; } catch (e) { rethrow; } } // for creating the payment request with Paypal Future<Map<String, String>> createPaypalPayment( transactions, accessToken) async { try { var response = await http.post("$domain/v1/payments/payment", body: convert.jsonEncode(transactions), headers: { "content-type": "application/json", 'Authorization': 'Bearer ' + accessToken }); final body = convert.jsonDecode(response.body); if (response.statusCode == 201) { if (body["links"] != null && body["links"].length > 0) { List links = body["links"]; String executeUrl = ""; String approvalUrl = ""; final item = links.firstWhere((o) => o["rel"] == "approval_url", orElse: () => null); if (item != null) { approvalUrl = item["href"]; } final item1 = links.firstWhere((o) => o["rel"] == "execute", orElse: () => null); if (item1 != null) { executeUrl = item1["href"]; } return {"executeUrl": executeUrl, "approvalUrl": approvalUrl}; } return null; } else { throw Exception(body["message"]); } } catch (e) { rethrow; } } // for executing the payment transaction Future<String> executePayment(url, payerId, accessToken) async { try { var response = await http.post(url, body: convert.jsonEncode({"payer_id": payerId}), headers: { "content-type": "application/json", 'Authorization': 'Bearer ' + accessToken }); final body = convert.jsonDecode(response.body); if (response.statusCode == 200) { return body["id"]; } return null; } catch (e) { rethrow; } } }
On an emulator of Android 10 it works fine for both sandbox and live.
However, on a physical Android 10 device (RedNote pro 9) the payment process is stuck on the PayPal screen, before loading the complete WebView:
Here is the log on RedNote device side:
02-08 10:54:27.819 I/Perf (17856): Connecting to perf service. 02-08 10:54:27.839 I/FeatureParser(17856): can't find joyeuse.xml in assets/device_features/,it may be in /vendor/etc/device_features 02-08 10:54:27.827 W/m.tortel.syslog(17856): type=1400 audit(0.0:197147): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=12172 scontext=u:r:untrusted_app:s0:c253,c256,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0 02-08 10:54:27.840 E/libc (17856): Access denied finding property "ro.vendor.df.effect.conflict" 02-08 10:54:27.866 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.870 I/chatty (17856): uid=10253(com.tortel.syslog) identical 6 lines 02-08 10:54:27.877 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.877 D/SysLog (17856): Fragment null, replacing 02-08 10:54:27.879 D/SysLog (17856): Loading settings 02-08 10:54:27.882 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.894 I/chatty (17856): uid=10253(com.tortel.syslog) identical 7 lines 02-08 10:54:27.895 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.895 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.897 I/chatty (17856): uid=10253(com.tortel.syslog) identical 3 lines 02-08 10:54:27.898 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.899 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.900 I/chatty (17856): uid=10253(com.tortel.syslog) identical 1 line 02-08 10:54:27.907 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.919 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.919 I/chatty (17856): uid=10253(com.tortel.syslog) identical 1 line 02-08 10:54:27.919 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.925 D/SysLog (17856): Checking for root 02-08 10:54:27.925 D/SysLog (17856): Setting the checkboxes 02-08 10:54:27.925 D/SysLog (17856): Checking if last_kmsg and radio are available 02-08 10:54:27.952 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.953 I/chatty (17856): uid=10253(com.tortel.syslog) identical 1 line 02-08 10:54:27.954 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.961 I/AdrenoGLES(17856): QUALCOMM build : 57da73e, I82b4603a7a 02-08 10:54:27.961 I/AdrenoGLES(17856): Build Date : 12/03/20 02-08 10:54:27.961 I/AdrenoGLES(17856): OpenGL ES Shader Compiler Version: EV031.27.05.03 02-08 10:54:27.961 I/AdrenoGLES(17856): Local Branch : 02-08 10:54:27.961 I/AdrenoGLES(17856): Remote Branch : refs/tags/AU_LINUX_ANDROID_LA.UM.8.9.R1.10.00.00.558.071 02-08 10:54:27.961 I/AdrenoGLES(17856): Remote Branch : NONE 02-08 10:54:27.961 I/AdrenoGLES(17856): Reconstruct Branch : NOTHING 02-08 10:54:27.961 I/AdrenoGLES(17856): Build Config : S P 8.0.12 AArch64 02-08 10:54:27.962 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.963 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:27.963 I/AdrenoGLES(17856): PFP: 0x016ee187, ME: 0x00000000 02-08 10:54:27.986 W/Gralloc3(17856): mapper 3.x is not supported 02-08 10:54:27.999 D/SysLog (17856): Root not available 02-08 10:54:28.026 D/SysLog (17856): Enabling log button: true 02-08 10:54:28.031 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:28.031 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:28.032 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:28.039 I/chatty (17856): uid=10253(com.tortel.syslog) identical 2 lines 02-08 10:54:28.040 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:29.798 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:29.798 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:29.800 V/SysLog (17856): Path: /data/user/0/com.tortel.syslog/cache/logs/2021-02-08_10.54/ 02-08 10:54:29.801 D/ForceDarkHelper(17856): updateByCheckExcludeList: pkg: com.tortel.syslog activity: com.tortel.syslog.FragmentMainActivity@b885376 02-08 10:54:29.806 V/SysLog (17856): Done grabbing logs