We recently released to our TWA (our app 
<https://play.google.com/store/apps/details?id=com.coursicle.coursicle&hl=en_US&gl=US>)
 
to customers and on day 1 are experiencing a very consistent issue with 
Google Play Billing. When we try to call getDetails() on a SKU as well as 
when we call listPurchases(), we receive a "DOMException: 
clientAppUnavailable", and the promise fails. Here are the tracebacks:

[image: image (4)] 
<https://user-images.githubusercontent.com/3255298/247774396-7f33fb3f-da3a-4efd-b109-c0d3c0ee8043.png>
[image: image (3)] 
<https://user-images.githubusercontent.com/3255298/247774381-dad48b4f-2343-4a89-90e7-8d71856618e8.png>

We are confident though that Play Services are being initialized:

[image: image (2)] 
<https://user-images.githubusercontent.com/3255298/247774151-af18d5c3-cc7e-45fb-8890-36d038a659a3.png>

After a lot of debugging, our current lead is that the issue may be with 
our Delegation Service. On Android 11, the Delegation Service runs and the 
extra command handler is registered successfully. On Android 13, the 
Delegation Service fails to run and a clientAppUnavailable DOM exception is 
raised. I've attached all of the files we believe are relevant 
(web_app_manifest.json, AndroidManifest.xml, build.gradle, 
DelegationService.kt, manifest-server.json) 
and here is our Javascript for making the purchase: 
https://pastebin.com/raw/qYhpQiBw. 

Here's our device information:

   - 
   
   Device: Galaxy A03s (working)
   - OS: Android 11
   - Browsers Installed: Chrome
   - Browser Versions: Chrome 114.0.5735.131
   - android-browser-helper library version: 2.4.0
   - 
   
   Device: Galaxy S22 Ultra (not working)
   - OS: Android 13
   - Browsers Installed: Chrome
   - Browser Versions: Chrome 114.0.5735.130
   - android-browser-helper library version: 2.4.0
   

Here's a comprehensive list of everything we've tried so far:

   - Clearing the Google Play Store Cache
   - Incrementing the targetSdkVersion in build.gradle from 33 to 34.
   - Ensuring the com.android.vending.BILLING permission is added to 
   AndroidManifest.xml
   - Ensuring that Google Play Services is up to date.
   - Done a line by line comparison with the PWA billing guide (
   https://chromeos.dev/en/publish/pwa-play-billing)


It seems like others have encountered this issue as well, although any fix 
they found did not work for us, and they in general were targeting older 
SDK versions:

   - 
   
https://stackoverflow.com/questions/74154396/why-does-the-digital-goods-apis-getservice-method-reject-with-clientappunavaila
   - clientAppUnavailable from getDetails GoogleChromeLabs/bubblewrap#640 
   (comment) 
   <https://github.com/GoogleChromeLabs/bubblewrap/issues/640#issue-1105007499>

Thank you so much for any assistance you can provide. We're really excited 
about our new PWA and this is the only major issue we've encountered during 
our conversion from native.


-- 
You received this message because you are subscribed to the Google Groups 
"Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to android-developers+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/android-developers/b6b8d20c-8ab0-47d0-a0ff-27a87ab90085n%40googlegroups.com.

Attachment: DelegationService.kt.gradle
Description: Binary data

Attachment: build.gradle
Description: Binary data

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android";
    xmlns:tools="http://schemas.android.com/tools";>
    <!--package="com.coursicle.coursicle" >-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="com.android.vending.BILLING" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

    <application
        android:name="CoursicleApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:manageSpaceActivity="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity"
        android:backupAgent=".MyBackupAgent">

        <meta-data android:name="com.google.android.backup.api_key"
                   android:value="[redacted]" />

        <!-- PWA Stuff -->
        <meta-data
            android:name="asset_statements"
            android:resource="@string/assetStatements" />

        <meta-data
            android:name="web_manifest_url"
            android:value="@string/webManifestUrl" />

        <meta-data
            android:name="twa_generator"
            android:value="@string/generatorApp" />

        <activity android:name="com.google.androidbrowserhelper.trusted.ManageDataLauncherActivity">
            <meta-data
                android:name="android.support.customtabs.trusted.MANAGE_SPACE_URL"
                android:value="@string/launchUrl" />
        </activity>

        <!--android:alwaysRetainTaskState="true"-->
        <activity android:name="LauncherActivity"
            android:label="@string/launcherName"
            android:exported="true"
            android:supportsRtl="true">

            <meta-data android:name="android.support.customtabs.trusted.DEFAULT_URL"
                android:value="@string/launchUrl" />
            <meta-data android:name="android.support.customtabs.trusted.STATUS_BAR_COLOR"
                android:resource="@color/navigationColor" />
            <meta-data android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR"
                android:resource="@color/navigationColor" />
            <meta-data android:name="android.support.customtabs.trusted.NAVIGATION_BAR_COLOR_DARK"
                android:resource="@color/navigationColorDark" />
            <meta-data android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR"
                android:resource="@color/navigationDividerColor" />
            <meta-data android:name="androix.browser.trusted.NAVIGATION_BAR_DIVIDER_COLOR_DARK"
                android:resource="@color/navigationDividerColorDark" />
            <meta-data android:name="android.support.customtabs.trusted.SPLASH_IMAGE_DRAWABLE"
                android:resource="@mipmap/ic_launcher"/>
            <meta-data android:name="android.support.customtabs.trusted.SPLASH_SCREEN_BACKGROUND_COLOR"
                android:resource="@color/backgroundColor"/>
            <meta-data android:name="android.support.customtabs.trusted.SPLASH_SCREEN_FADE_OUT_DURATION"
                android:value="@integer/splashScreenFadeOutDuration"/>
            <meta-data android:name="android.support.customtabs.trusted.FILE_PROVIDER_AUTHORITY"
                android:value="@string/providerAuthority"/>
            <!--meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" /-->
            <meta-data android:name="android.support.customtabs.trusted.FALLBACK_STRATEGY"
                android:value="@string/fallbackType" />
            <meta-data android:name="android.support.customtabs.trusted.SCREEN_ORIENTATION"
                android:value="@string/orientation"/>

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:host="daniel.coursicle.com"
                android:scheme="https" />
            </intent-filter>
        </activity>

        <activity android:name="com.google.androidbrowserhelper.trusted.FocusActivity" />

        <activity android:name="com.google.androidbrowserhelper.trusted.WebViewFallbackActivity"
            android:configChanges="orientation|screenSize" />

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="@string/providerAuthority"
            android:grantUriPermissions="true"
            android:exported="false">

            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/filepaths" />
        </provider>

        <service
            android:name=".DelegationService"
            android:enabled="true"
            android:exported="true">

            <meta-data
                android:name="android.support.customtabs.trusted.SMALL_ICON"
                android:resource="@mipmap/ic_launcher" />

            <intent-filter>
                <action android:name="android.support.customtabs.trusted.TRUSTED_WEB_ACTIVITY_SERVICE"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

            <!--
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            -->
        </service>
        <activity
            android:name="com.google.androidbrowserhelper.playbilling.provider.PaymentActivity"
            android:theme="@android:style/Theme.Translucent.NoTitleBar"
            android:configChanges="keyboardHidden|keyboard|orientation|screenLayout|screenSize"
            android:exported="true">
            <intent-filter>
                <action android:name="org.chromium.intent.action.PAY" />
            </intent-filter>
            <meta-data
                android:name="org.chromium.default_payment_method_name"
                android:value="https://play.google.com/billing"; />
        </activity>
        <!-- This service checks who calls it at runtime. -->
        <service
            android:name="com.google.androidbrowserhelper.playbilling.provider.PaymentService"
            android:exported="true" >
            <intent-filter>
                <action android:name="org.chromium.intent.action.IS_READY_TO_PAY" />
            </intent-filter>
        </service>
    </application>
</manifest>

Attachment: manifest-server.json
Description: application/json

Attachment: web_app_manifest.json
Description: Binary data

Reply via email to