@@ -2,9 +2,16 @@ package com.stripe.android.shoppay
2
2
3
3
import android.content.Context
4
4
import android.content.Intent
5
+ import android.net.Uri
6
+ import android.os.Build
5
7
import android.os.Bundle
8
+ import android.view.ViewGroup
9
+ import android.webkit.WebResourceRequest
10
+ import android.webkit.WebView
11
+ import android.webkit.WebViewClient
6
12
import androidx.activity.ComponentActivity
7
13
import androidx.activity.compose.setContent
14
+ import androidx.annotation.RequiresApi
8
15
import androidx.compose.foundation.layout.Box
9
16
import androidx.compose.foundation.layout.Column
10
17
import androidx.compose.foundation.layout.fillMaxSize
@@ -19,6 +26,7 @@ import androidx.compose.ui.Alignment
19
26
import androidx.compose.ui.Modifier
20
27
import androidx.compose.ui.res.painterResource
21
28
import androidx.compose.ui.unit.dp
29
+ import androidx.compose.ui.viewinterop.AndroidView
22
30
import androidx.core.os.BundleCompat
23
31
import androidx.core.os.bundleOf
24
32
import com.stripe.android.common.ui.BottomSheetScaffold
@@ -60,6 +68,8 @@ internal class ShopPayActivity : ComponentActivity() {
60
68
}
61
69
) {
62
70
BottomSheetScaffold (
71
+ // modifier = Modifier
72
+ // .fillMaxSize(),
63
73
topBar = {
64
74
Box (
65
75
modifier = Modifier
@@ -80,31 +90,59 @@ internal class ShopPayActivity : ComponentActivity() {
80
90
}
81
91
},
82
92
content = {
83
- Column (
84
- modifier = Modifier
85
- .fillMaxSize()
86
- ) {
87
- Button (
88
- onClick = {
89
- dismissWithResult(ShopPayActivityResult .Completed (" pm_1234" ))
90
- }
91
- ) {
92
- Text (" Complete" )
93
- }
94
-
95
- Button (
96
- onClick = {
97
- dismissWithResult(ShopPayActivityResult .Failed (Throwable (" Failed" )))
98
- }
99
- ) {
100
- Text (" Fail" )
101
- }
102
- }
93
+ ComposeWebView ()
94
+ // Column(
95
+ // modifier = Modifier
96
+ // .fillMaxSize()
97
+ // ) {
98
+ // Button(
99
+ // onClick = {
100
+ // dismissWithResult(ShopPayActivityResult.Completed("pm_1234"))
101
+ // }
102
+ // ) {
103
+ // Text("Complete")
104
+ // }
105
+ //
106
+ // Button(
107
+ // onClick = {
108
+ // dismissWithResult(ShopPayActivityResult.Failed(Throwable("Failed")))
109
+ // }
110
+ // ) {
111
+ // Text("Fail")
112
+ // }
113
+ // }
103
114
}
104
115
)
105
116
}
106
117
}
107
118
119
+ @Composable
120
+ private fun ComposeWebView () {
121
+ // Declare a string that contains a url
122
+ val mUrl = " https://www.google.com"
123
+
124
+ // Adding a WebView inside AndroidView
125
+ // with layout as full screen
126
+ AndroidView (
127
+ modifier = Modifier
128
+ .fillMaxSize(),
129
+ factory = {
130
+ WebView (it).apply {
131
+ layoutParams = ViewGroup .LayoutParams (
132
+ ViewGroup .LayoutParams .MATCH_PARENT ,
133
+ ViewGroup .LayoutParams .MATCH_PARENT
134
+ )
135
+ settings.javaScriptEnabled = true
136
+ }
137
+ }, update = {
138
+ it.webViewClient = CustomWebViewClient { id, addressLine1 ->
139
+ dismissWithResult(ShopPayActivityResult .Completed (id, addressLine1))
140
+ }
141
+ it.loadDataWithBaseURL(null , RAW_HTML , " text/html" , " UTF-8" , null )
142
+ // it.loadUrl(mUrl)
143
+ })
144
+ }
145
+
108
146
private fun dismissWithResult (result : ShopPayActivityResult ) {
109
147
val bundle = bundleOf(
110
148
ShopPayActivityContract .EXTRA_RESULT to result
@@ -113,6 +151,44 @@ internal class ShopPayActivity : ComponentActivity() {
113
151
finish()
114
152
}
115
153
154
+ private class CustomWebViewClient (
155
+ private val onComplete : (String , String ) -> Unit
156
+ ): WebViewClient() {
157
+ @RequiresApi(Build .VERSION_CODES .LOLLIPOP )
158
+ override fun shouldOverrideUrlLoading (view : WebView , request : WebResourceRequest ): Boolean {
159
+ return handleUrl(request.url.toString())
160
+ }
161
+
162
+ // For API below 21
163
+ @Suppress(" OverridingDeprecatedMember" )
164
+ override fun shouldOverrideUrlLoading (view : WebView , url : String ): Boolean {
165
+ return handleUrl(url)
166
+ }
167
+
168
+ private fun handleUrl (url : String ): Boolean {
169
+
170
+ // Check if it's our stripe URL scheme
171
+ if (url.startsWith(" stripe://" )) {
172
+ // Parse the URL
173
+ val uri = Uri .parse(url)
174
+ val paymentMethodId = uri.getQueryParameter(" paymentMethodId" )
175
+ ? : throw IllegalStateException (" No paymentMethodId" )
176
+ val addressLine1 = uri.getQueryParameter(" address.line1" )
177
+ ? : throw IllegalStateException (" No address" )
178
+
179
+ // Process the payment
180
+ // processPayment(paymentMethodId, addressLine1)
181
+ onComplete(paymentMethodId, addressLine1)
182
+
183
+ // Return true to indicate we handled the URL
184
+ return true
185
+ }
186
+
187
+ // For all other URLs, let the WebView handle it normally
188
+ return false
189
+ }
190
+ }
191
+
116
192
companion object {
117
193
internal const val EXTRA_ARGS = " shop_pay_args"
118
194
internal const val RESULT_COMPLETE = 63636
@@ -126,3 +202,45 @@ internal class ShopPayActivity : ComponentActivity() {
126
202
}
127
203
}
128
204
}
205
+
206
+ private const val RAW_HTML = """
207
+ <!DOCTYPE html>
208
+ <html lang="en">
209
+ <head>
210
+ <meta charset="UTF-8">
211
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
212
+ <title>Shop Pay</title>
213
+ <style>
214
+ body {
215
+ font-family: Arial, sans-serif;
216
+ max-width: 600px;
217
+ margin: 0 auto;
218
+ padding: 20px;
219
+ text-align: center;
220
+ }
221
+ h1 {
222
+ color: #5A31F4;
223
+ margin-bottom: 30px;
224
+ }
225
+ .checkout-button {
226
+ background-color: #5A31F4;
227
+ color: white;
228
+ border: none;
229
+ padding: 12px 24px;
230
+ font-size: 16px;
231
+ border-radius: 4px;
232
+ cursor: pointer;
233
+ transition: background-color 0.3s;
234
+ }
235
+ .checkout-button:hover {
236
+ background-color: #4526C3;
237
+ }
238
+ </style>
239
+ </head>
240
+ <body>
241
+ <h1>Welcome to Shop Pay</h1>
242
+ <button class="checkout-button" onclick="window.location.href = 'stripe://action?paymentMethodId=pm_123456758&address.line1=123%20main';">Checkout</button>
243
+ </body>
244
+ </html>
245
+
246
+ """
0 commit comments