Search code examples
androidapkwear-osgoogle-play-console

Packaging separate wear apks for android wear 1.x and 2.0


I am attempting to create a standalone Android Wear app for 1.x and 2. I followed the steps on the android developer page, but users say the wear apk isn't automatically installing on their 1.x watch. The mobile app has the same permissions. This is only here to get the wear apk to install. There are no activities on the mobile app.

Do I need to package the wear app in my mobile app? From what I read this shouldn't be done even for 1.x.

Here is a preview of what my apks look like in the developer console: enter image description here

Mobile Manifest:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher"
    android:supportsRtl="true"
    android:theme="@style/Theme.Nav">

</application>

Wear Manifest:

<?xml version="1.0" encoding="utf-8"?>

<uses-feature android:name="android.hardware.type.watch" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

<!-- Required for complications to receive complication data and open the provider chooser. -->
<uses-permission android:name="com.google.android.wearable.permission.RECEIVE_COMPLICATION_DATA"/>

<application
    android:name=".App"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher"
    android:supportsRtl="true"
    android:theme="@style/Theme.Nav">
    <uses-library
        android:name="com.google.android.wearable"
        android:required="false" />

    <meta-data
        android:name="com.google.android.wearable.standalone"
        android:value="true" />

    <activity android:name=".ui.activity.SplashActivity"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Translucent.NoTitleBar">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

    <!-- Main activity for music browsing on phone -->
    <activity android:name=".ui.activity.MainActivity"
        android:launchMode = "singleTop">
    </activity>

    <service android:name=".service.MediaPlayerService" />

    <activity android:name="android.support.wearable.activity.ConfirmationActivity" />

    <!--
     Main music service, provides media browsing and media playback services to
     consumers through MediaBrowserService and MediaSession. Consumers connect to it through
     MediaBrowser (for browsing) and MediaController (for play session control)
    -->

    <service android:name=".service.FsService" />
    <service android:name=".service.NsdService" />

    <receiver
        android:name=".service.NsdService$StartStopReceiver"
        android:exported="false">
        <intent-filter>
            <action android:name="com.turndapage.navmusic.FTPSERVER_STARTED" />
            <action android:name="com.turndapage.navmusic.FTPSERVER_STOPPED" />
        </intent-filter>
    </receiver>

    <!-- Don't export this receiver in free, this clashes with paid -->
    <receiver
        android:name=".RequestStartStopReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="com.turndapage.navmusic.ACTION_START_FTPSERVER" />
            <action android:name="com.turndapage.navmusic.ACTION_STOP_FTPSERVER" />
        </intent-filter>
    </receiver>
    <receiver android:name=".WifiStateChangeReceiver">
        <intent-filter>
            <action android:name="android.net.wifi.STATE_CHANGE" />
        </intent-filter>
    </receiver>

    <service android:name=".WifiStateChangeReceiver$StartServerService" />
    <service android:name=".WifiStateChangeReceiver$StopServerService" />

    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />

    <service
        android:name=".watchface.AnalogComplicationWatchFaceService"
        android:enabled="true"
        android:label="@string/my_analog_name"
        android:permission="android.permission.BIND_WALLPAPER">
        <meta-data
            android:name="android.service.wallpaper"
            android:resource="@xml/watch_face" />
        <meta-data
            android:name="com.google.android.wearable.watchface.preview"
            android:resource="@drawable/preview_analog" />
        <meta-data
            android:name="com.google.android.wearable.watchface.preview_circular"
            android:resource="@drawable/preview_analog" />
        <meta-data
            android:name="com.google.android.wearable.watchface.wearableConfigurationAction"
            android:value="com.turndapage.navmusic.CONFIG_COMPLICATION_SIMPLE"/>

        <intent-filter>
            <action android:name="android.service.wallpaper.WallpaperService" />

            <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
        </intent-filter>
    </service>

    <activity android:name="android.support.wearable.complications.ComplicationHelperActivity"/>
    <activity
        android:name=".config.AnalogComplicationConfigActivity"
        android:label="@string/analog_complication_config">
        <intent-filter>
            <action android:name="com.turndapage.navmusic.CONFIG_COMPLICATION_SIMPLE"/>

            <category android:name="com.google.android.wearable.watchface.category.WEARABLE_CONFIGURATION"/>
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>
    </activity>

    <receiver android:name=".provider.ComplicationToggleReceiver"/>

    <activity android:name=".config.ColorSelectionActivity"/>

    <service android:name=".provider.CurrentSongComplicationProvider"
        android:icon="@drawable/ic_library_music_white_24dp"
        android:label="@string/current_song"
        android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
        <intent-filter>
            <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
        </intent-filter>

        <meta-data
            android:name="android.support.wearable.complications.SUPPORTED_TYPES"
            android:value="SHORT_TEXT,LONG_TEXT"/>

        <meta-data
            android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
            android:value="0"/>
    </service>

    <service android:name=".provider.SkipBackComplicationProvider"
        android:icon="@drawable/ic_skip_previous_white_24dp"
        android:label="@string/skip_back"
        android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
        <intent-filter>
            <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
        </intent-filter>

        <meta-data
            android:name="android.support.wearable.complications.SUPPORTED_TYPES"
            android:value="ICON"/>

        <meta-data
            android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
            android:value="0"/>
    </service>

    <service android:name=".provider.SkipForwardComplicationProvider"
        android:icon="@drawable/ic_skip_next_white_24dp"
        android:label="@string/skip_next"
        android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
        <intent-filter>
            <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
        </intent-filter>

        <meta-data
            android:name="android.support.wearable.complications.SUPPORTED_TYPES"
            android:value="ICON"/>

        <meta-data
            android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
            android:value="0"/>
    </service>

    <service android:name=".provider.PlayPauseComplicationProvider"
        android:icon="@drawable/ic_media_play_dark"
        android:label="@string/play_pause"
        android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
        <intent-filter>
            <action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
        </intent-filter>

        <meta-data
            android:name="android.support.wearable.complications.SUPPORTED_TYPES"
            android:value="ICON"/>

        <meta-data
            android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
            android:value="0"/>
    </service>

    <!-- Watch face stuff -->

</application>

Mobile Gradle:

apply plugin: 'com.android.application'

android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
    applicationId "com.turndapage.navmusic"
    minSdkVersion 15
    targetSdkVersion 26
    versionCode 260350011
    versionName "0.3.5"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    wearAppUnbundled true
}
buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

repositories {
jcenter()
maven {
    url 'https://maven.google.com'
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', 
{
    exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:26.0.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
}

Wear gradle:

plugins {
id "me.tatarka.retrolambda" version "3.5.0"
}
apply plugin: 'com.android.application'

android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
    applicationId "com.turndapage.navmusic"
    minSdkVersion 23
    targetSdkVersion 26
    versionCode 260350010
    versionName "0.3.5"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
// Needed for retrolambda
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
}

repositories {
jcenter()
maven {
    url 'https://maven.google.com'
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.android.support:wearable:2.0.3'
compile 'com.android.support:wear:26.0.1'
compile 'com.google.android.gms:play-services-wearable:11.0.4'
compile 'com.google.android.exoplayer:exoplayer:r2.4.1'
compile 'de.hdodenhof:circleimageview:1.3.0'
compile 'com.google.code.gson:gson:2.7'
compile 'com.github.kabouzeid:app-theme-helper:1.3.7'
compile 'com.android.support:support-v4:26.0.1'
compile 'com.android.support:design:26.0.1'
compile 'com.android.support:appcompat-v7:26.0.1'
compile 'com.android.support:preference-v7:26.0.1'
compile 'com.android.support:mediarouter-v7:26.0.1'
compile 'com.android.support:percent:26.0.1'
compile 'net.vrallev.android:cat:1.0.5'
compile 'org.projectlombok:lombok:1.16.18'
compile 'com.twofortyfouram:android-plugin-client-sdk-for-locale:4.0.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.github.bumptech.glide:glide:4.0.0-RC1'
compile 'com.google.android.gms:play-services-fitness:11.0.4'
compile 'com.android.support:palette-v7:26.0.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC1'
provided 'com.google.android.wearable:wearable:2.0.3'
}

[Edit] I had to update to include complication permissions and remove the watch feature on the mobile app to get it to upload to the play store. Some users report it is installing, but others can't get it to work.


Solution

  • Your assumption is correct, you should not embed the wear APK inside the phone APK (this was the old way of doing it). However, you still need to publish the phone APK.

    There are only 2 APKs in your screen shot. There should be 3 in total: phone APK for AW 1.x, wear APK for AW 1.x, and wear APK for AW 2.x.

    Make sure that the AW 2.0 APK has the highest version code, followed by the AW 1.x watch APK, and finally the AW 1.x phone APK.

    Note that that the wearAppUnbundled true flag (in your phone gradle file) is only needed if you've previously published an AW 1.x app with an embedded wear APK (but it shouldn't hurt to include it otherwise).