Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
70a50d3
Change view layout
marcosrivereto Aug 26, 2025
b366073
Create utils functions
marcosrivereto Aug 26, 2025
2e4a809
Call widget and lightbox in ASWebAuthenticationSession component
marcosrivereto Aug 26, 2025
e9aba0d
Remove unused code
marcosrivereto Aug 27, 2025
f2a303f
Add urlScheme in return and cancel url
marcosrivereto Aug 27, 2025
65888b4
Remove metadata.integrationContext to handle with oAuth flow
marcosrivereto Aug 27, 2025
3034348
Remove sensitive data
marcosrivereto Aug 27, 2025
bdd8906
Update README files
marcosrivereto Aug 28, 2025
01a7e97
Fix typo
marcosrivereto Aug 29, 2025
695e44f
Updating dependencies
andresguedes Sep 4, 2025
5353802
Some refactoring
andresguedes Sep 4, 2025
cf27cf4
Changing main screen
andresguedes Sep 4, 2025
ccc6970
Opening in app browser screen with boolean value
andresguedes Sep 4, 2025
4380fc5
Removing unused classes
andresguedes Sep 4, 2025
8041f99
Opening url on custom tabs
andresguedes Sep 4, 2025
c1144e9
Adding establish data params
andresguedes Sep 4, 2025
09c6e7d
Changing style
andresguedes Sep 4, 2025
b162d92
Renaming util class
andresguedes Sep 4, 2025
fea2c44
Changing readme files
andresguedes Sep 4, 2025
e4cdb5b
Adding missing establish data params
andresguedes Sep 4, 2025
25e9dcd
Add instructions for enviroments
pedroabdenor Sep 9, 2025
ca81cb7
Merge pull request #25 from TrustlyInc/dev-243717-ios-document-custom…
pedroabdenor Sep 11, 2025
57175e2
Merge pull request #27 from TrustlyInc/DEV-251930-documentation_inapp…
pedroabdenor Sep 11, 2025
e6cf661
Add instructions for enviroments
pedroabdenor Sep 11, 2025
56025f9
Merge pull request #28 from TrustlyInc/DEV-265362-remove-webapp
pedroabdenor Sep 11, 2025
6e76907
Adding validation for app to app flow
andresguedes Oct 13, 2025
a1aa18e
Adding dialog for success or failure message
andresguedes Oct 14, 2025
716509b
Merge pull request #31 from Trustly-Samples/DEV-287160-success_failur…
andresguedes Oct 15, 2025
9f9adcc
Merge pull request #30 from Trustly-Samples/DEV-287119-fix_oauth_appt…
andresguedes Oct 15, 2025
d6236b5
Add token implemetation and fix buttons on android
pedroabdenor Oct 24, 2025
49dfcdf
Fixing variable reference
andresguedes Nov 24, 2025
b6055c6
Finishing activity to prevent blank on return
andresguedes Nov 25, 2025
3800669
Merge pull request #33 from Trustly-Samples/DEV-289253-fix_return_bla…
andresguedes Nov 26, 2025
0ecd52b
Fixing dialog persistence
andresguedes Nov 26, 2025
6c45b15
Merge pull request #34 from Trustly-Samples/DEV-290432-fix_dialog_per…
andresguedes Nov 27, 2025
4dccc78
Removing special chars
andresguedes Dec 17, 2025
d49b283
Removing missing char
andresguedes Dec 23, 2025
0114652
Merge pull request #35 from Trustly-Samples/DEV-287173-fix_internal_e…
andresguedes Dec 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
# Trustly Mobile Webview Example App
# Trustly Mobile In-app Browser Example App

<img src="https://user-images.githubusercontent.com/13320316/255275758-068fbcd2-b681-4fdb-a914-15ba1c875c5a.png" alt="screenshot of example app" width="250">

This project is provided as an example of integration between a web app serving the Trustly UI and mobile apps that render that web app from a webview. Specifically, this example focuses on successfully handling OAuth and App-to-App bank authorization user flows. The repository can be used alongside Trustly's [Mobile App Webview tutorial](https://amer.developers.trustly.com/payments/docs/oauth-for-mobile-apps).

## The Web App

The `react-web-app` directory contains a simple React app that displays a "Pay with Trustly" button which launches the Lightbox. Instructions for running this app can be found in that directory's [ReadMe](./react-web-app/README.md).
This project is provided as an example of integrating Trustly’s hosted UI within a mobile app using an in-app browser. It demonstrates how to handle OAuth and App-to-App bank authorization flows when the app simply opens a Trustly URL. The repository can be used alongside Trustly’s mobile App In-app Browser tutorial.

## The iOS App

The `ios-app` directory contains a simple Swift app that renders a Webview of a given URL. With the above React app running, the iOS app can be pointed to the resulting URL to demonstrate the webview and secure-in-app-browser functionality required to successfully integrate the two applications. Additional instructions can be found in that directory's [ReadMe](./ios-app/README.md).
The `ios-app` directory contains a simple Swift app that launches an OAuth web authentication session. Additional instructions can be found in Trustly’s mobile In-app Browser tutorial.

## The Android App

The `android-app` directory contains a simple Kotlin app that renders a Webview of a given URL. With the above React app running, the Android app can be pointed to the resulting URL to demonstrate the webview and secure-in-app-browser functionality required to successfully integrate the two applications. Additional instructions can be found in that directory's [ReadMe](./android-app/README.md).
The `android-app` directory contains a simple Android Kotlin app that launches an OAuth web authentication session. Additional instructions can be found in Trustly’s mobile In-app Browser tutorial.

# Contributing

You can participate in this project by submitting bugs and feature requests in the [Issues](https://github.com/TrustlyInc/trustly-webview-example/issues) tab.

If you are interested in fixing issues and contributing directly to the code base, feel free to open a Pull Request with your changes. Please, make sure to fulfill our [Pull Request Template](https://github.com/TrustlyInc/trustly-webview-example/blob/main/.github/pull_request_template.md).
If you are interested in fixing issues and contributing directly to the code base, feel free to open a Pull Request with your changes. Please, make sure to fulfill our [Pull Request Template](https://github.com/TrustlyInc/trustly-webview-example/blob/main/.github/pull_request_template.md).
6 changes: 6 additions & 0 deletions android-app/.idea/AndroidProjectSystem.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion android-app/.idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android-app/.idea/copilot.data.migration.agent.xml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these copilot related files can be added to .gitignore. Can you confirm?

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android-app/.idea/copilot.data.migration.ask.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android-app/.idea/copilot.data.migration.ask2agent.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android-app/.idea/copilot.data.migration.edit.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions android-app/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions android-app/.idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions android-app/.idea/migrations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion android-app/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions android-app/.idea/runConfigurations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 23 additions & 63 deletions android-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,34 @@ This app demo has a propose to demonstrate how to implement the oauth authentica

`Chrome Custom Tabs` has no method to close itself, and this implementation is based on redirecting to previous Activity, by Intent flags, finishing the called Activity with registered scheme.


## Introduction

These are some example how to implement a sign-in on OAuth flow to use Trustly JavaScript SDK.
The code is using Kotlin language implementation.

## WebClient

There are two ways to create web clients for a WebView, `WebViewClient` and `WebChromeClient`.
To open Trustly widget or lightbox we need to build an url with a `token`. This `token` is the `establish data` in `base 64` format.

### WebViewClient implementation
### Building url
The base url is `https://sandbox.paywithmybank.com/frontend/mobile/establish`.

Using `WebViewClient` you'll need to add a configuration in the `settings` property.
Set the `javaScriptCanOpenWindowsAutomatically` property to true in order to enable the application to properly handle `window.open` events.
`Establish data` is a dictionary with all parameters to create a transaction, to transform `establish data` to `base 64` format we should convert the dicitionary in a `json string` and after that create the `base 64` value.

```kotlin
webView.settings.apply {
javaScriptCanOpenWindowsAutomatically = true
}
val establishData = JSONUtils.getJsonFromParameters(getEstablishDataValues(this))
val establishDataBase64 = JSONUtils.encodeStringToBase64(establishData)
```

Using `WebViewClient` you can override many methods, but you need to implement the `shouldOverrideUrlLoading` method. This method determines what will happen when a URL is loaded in WebView.
The example below is a simple implementation that calls the method which opens the CustomTabs.
The `JSONUtils` class, is a custom class created by Trustly, you can check the content in the file `JSONUtils.kt`.

```kotlin
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
val url = request.url.toString()
if (url.contains(TrustlyConstants.OAUTH_LOGIN_PATH))
launchUrl(this@WebViewClientActivity, url)
return true
}
}
```

### WebChromeClient implementation
In the url, you can send the `widget` parameter, to ask to open the `widget` if the `true`, or the lightbox, if `false`.

Using `WebChromeClient` you'll need to create your own WebView, add some configuration in the `settings` property, and transport itself to a custom WebView.
The example below explain more about those implementation. First you need to add both `javaScriptCanOpenWindowsAutomatically` and `setSupportMultipleWindows(true)`, they are needed to listen the `window.open` method.
The complete url with `base 64` `token` and `widget` parameter as `true`.

```kotlin
webView.settings.apply {
javaScriptCanOpenWindowsAutomatically = true
setSupportMultipleWindows(true)
}
https://sandbox.paywithmybank.com/frontend/mobile/establish?widget=true&token=eyJhY2Nlc3NJZCI6IkE0OEI3M0Y2OTRDNEM4RUU2MzA2IiwicGF5bWVudFR5cGUiOiJSZXRyaWV2YWwiLCJmbG93VHlwZSI6IiIsIm1ldGFkYXRhIjp7InNka0lPU1ZlcnNpb24iOiIzLjMuMCIsInVybFNjaGVtZSI6ImRlbW9hcHA6XC9cLyIsImNpZCI6IjEwRjYtNENFQy1NRVQwWERIUSIsInRoZW1lIjoiZGFyayJ9LCJzZXNzaW9uQ2lkIjoiMTBGNi00NDFBLU1FVDBCV0c0IiwicmV0dXJuVXJsIjoiZGVtb2FwcDpcL1wvIiwicmVxdWVzdFNpZ25hdHVyZSI6IkhUNW1WT3FCWGE4Wmx2Z1gyVVNtUGVMbnM1bz0iLCJ0aGVtZSI6ImRhcmsiLCJ2ZXJzaW9uIjoiMiIsImVudiI6InNhbmRib3giLCJjdXJyZW5jeSI6IlVTRCIsIm1lcmNoYW50SWQiOiIxMTAwMDU1MTQiLCJjYW5jZWxVcmwiOiJkZW1vYXBwOlwvXC8iLCJtZXJjaGFudFJlZmVyZW5jZSI6ImNhYzczZGY3LTUyYjQtNDdkNy04OWQzLTk2MjhkNGNmYjY1ZSIsImVudkhvc3QiOiIxOTIuMTY4LjAuMTMiLCJwYXltZW50UHJvdmlkZXJJZCI6IjIwMDAwNTUwMSIsImdycCI6IjE4Iiwid2lkZ2V0TG9hZGVkIjoidHJ1ZSIsImN1c3RvbWVyIjp7ImFkZHJlc3MiOnsiY291bnRyeSI6IlVTIn0sIm5hbWUiOiJKb2huIn0sImRldmljZVR5cGUiOiJtb2JpbGU6aW9zOm5hdGl2ZSIsImFtb3VudCI6IjEwLjAwIiwiZGVzY3JpcHRpb24iOiJGaXJzdCBEYXRhIE1vYmlsZSBUZXN0In0=
```

This is the `WebChromeClient` implementation, using a custom WebView to transport the URL and than open it inside that.
The `trustlyWebView` is an instance of the custom WebView, which has the same implementation of a `WebViewClient`.

```kotlin
webView.webChromeClient = object : WebChromeClient() {
override fun onCreateWindow(view: WebView, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message): Boolean {
return if (view.hitTestResult.type == 0) {
//window.open
webView.addView(trustlyWebView)
val transport = resultMsg.obj as WebViewTransport
transport.webView = trustlyWebView.webView
resultMsg.sendToTarget()
true
} else false
}
}
```
After built Trustly url, now, you can open widget or lightbox with oAuth component.

### CustomTabsIntent

Expand All @@ -80,41 +44,37 @@ In your custom web view you need to create a CustomTabIntent to open the url:
```kotlin
private fun launchUrl(context: Context, url: String) {
val customTabsIntent = CustomTabsIntent.Builder().build()
customTabsIntent.intent.setPackage("com.android.chrome")
customTabsIntent.launchUrl(context, Uri.parse(url))
}
```

### TrustlyWebChromeClientRedirectActivity and TrustlyWebViewClientRedirectActivity
### RedirectActivity

When the application receive some action for example `web-chrome-client-redirect`, or the name that you defined in `urlScheme`, it will call your target Activity with some flags, and reload it.
The example below is from `TrustlyWebChromeClientRedirectActivity`
When the application receive some action for example `in-app-browser-android`, or the name that you defined in `urlScheme`, it will call your target Activity with some flags, and reload it.
We added a validation for in case the return information has no transaction data, for example in the app-to-app OAuth flow.
The example below is from `RedirectActivity`

```kotlin
Intent(this, WebChromeClientActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}.run { startActivity(this) }
if (intent.extras != null && intent.data!!.getQueryParameter(STATUS_PARAM) != null) {
Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}.run { startActivity(this) }
}
finish()
```

### AndroidManifest

```xml
<activity
android:name=".TrustlyWebChromeClientRedirectActivity"
android:name=".RedirectActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="web-chrome-client-redirect" />
<data android:scheme="@string/url_scheme" />
</intent-filter>
</activity>
```

### ProceedToChooseAccount

Finally, in order to support a smooth user experience when an OAuth login authorization is completed and the user returns to the Lightbox, call this function using some code like this:

```kotlin
webView.loadUrl("javascript:window.Trustly.proceedToChooseAccount();")
```
15 changes: 8 additions & 7 deletions android-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {

android {
namespace 'net.trustly.inappbrowserandroid'
compileSdk 33
compileSdk 36

defaultConfig {
applicationId "net.trustly.inappbrowserandroid"
Expand Down Expand Up @@ -33,11 +33,12 @@ android {
}

dependencies {
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.browser:browser:1.5.0'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.core:core-ktx:1.17.0'
implementation 'androidx.appcompat:appcompat:1.7.1'
implementation 'androidx.browser:browser:1.9.0'
implementation 'com.google.android.material:material:1.13.0'
implementation 'com.google.code.gson:gson:2.13.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
}
30 changes: 4 additions & 26 deletions android-app/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,20 @@
</intent-filter>
</activity>
<activity
android:name=".WebViewBaseActivity"
android:exported="true" />
<!-- WebViewClient -->
<activity
android:name=".webviewclient.WebViewClientActivity"
android:exported="true"
android:label="@string/webview_client" />
<activity
android:name=".webviewclient.TrustlyWebViewClientRedirectActivity"
android:name=".RedirectActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="web-view-client-redirect" />
<data android:scheme="@string/url_scheme" />
</intent-filter>
</activity>
<!-- WebChromeClient -->
<activity
android:name=".webchromeclient.WebChromeClientActivity"
android:exported="true"
android:label="@string/webchrome_client" />
<activity
android:name=".webchromeclient.TrustlyWebChromeClientRedirectActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="web-chrome-client-redirect" />
</intent-filter>
</activity>
android:name=".InAppBrowserActivity"
android:exported="false" />
</application>

</manifest>
Loading
Loading