且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Android Wear应用程序不是通过手机上安装

更新时间:2022-12-29 23:07:15

要回答@odiggity具体而言,在 build.gradle 您的手机应用程序文件,你应该提到的确切的名称穿app文件夹的。如果您在创建该项目的 Android的工作室的,那么你的build.gradle应该是这样的:

  wearApp项目(:穿)
 

这可能发生,因为以下原因:

  • 在服装及放大器;移动应用程序的权限不一样的。

这是没有任何地方记录在开发者网站上,但我发现这和我的个人经验。究其原因,我能想到这背后的限制是,谷歌想要的 prevent偷偷摸摸的开发的利用用户和放大器;他们的隐私。

  • 磨损和放包的名称;移动应用程序不匹配。
  • 移动和放大器的应用ID (build.gradle文件);戴应用程序不匹配。
  • 资产的COM pression

如果你正在使用Eclipse进行开发,请务必关闭资产的COM pression,否则在原文件夹中的.apk文件文件将获得双COM pressed &放大器;在手机将无法识别如果移动应用是包装磨损应用程序或没有。

***的解决方案:

使用Android的工作室。

  1. 创建Android项目
  2. 选择电话和放大器;磨损项目
  3. 按照步骤创建项目
  4. 复制所有的磨损应用程序使用移动应用程序的清单或副权限反之亦然

I'm trying to get a wearable app installed through an Android handset using the 'Package with Android Studio method' found here but it's not working. The apk is never installed to the wearable device. This is the logcat output:

07-28 15:11:54.107      766-820/? W/PackageManager﹕ Unknown permission com.google.android.wearable.READ_SETTINGS in package com.google.android.gms
07-28 15:11:54.117      766-820/? W/PackageManager﹕ Not granting permission com.google.android.gm.permission.AUTO_SEND to package com.google.android.wearable.app (protectionLevel=2 flags=0x88be44)
07-28 15:11:54.117      766-820/? W/PackageManager﹕ Not granting permission android.permission.MEDIA_CONTENT_CONTROL to package com.google.android.wearable.app (protectionLevel=18 flags=0x88be44)
07-28 15:11:55.047      632-632/? D/WearablePkgInstaller﹕ Got PackageUpdateReceiver message Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:my.package.name flg=0x4000010 cmp=com.google.android.wearable.app/com.google.android.clockwork.companion.packagemanager.PackageUpdateReceiver (has extras) }
07-28 15:11:55.177      632-632/? D/WearablePkgInstaller﹕ Got PackageUpdateReceiver message Intent { act=android.intent.action.PACKAGE_ADDED dat=package:my.package.name flg=0x4000010 cmp=com.google.android.wearable.app/com.google.android.clockwork.companion.packagemanager.PackageUpdateReceiver (has extras) }

As a side note I am able to package manually (also described in the link above) and the apk gets installed on the wearable device when I run it on the handset. I am using buildToolsVersion 20.0.0, I'm running Android Studio 0.8.2 and have this line in my handset module's build.gradle:

wearApp project(':wearable')

I've run out of ideas on how to debug this, the logs seem pretty useless. Any ideas?

EDIT: Going to post relevant sections of Manifest and build.gradle for both the handset and wearable module.

Handset Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="my.package.name"
          android:installLocation="auto"
          android:versionCode="259"
          android:versionName="4.6.1">

    <!-- =========== -->
    <!-- PERMISSIONS -->
    <!-- =========== -->

    <permission
        android:name="my.app.name.permission.C2D_MESSAGE"
        android:protectionLevel="signature"/>

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

    <!-- ====================== -->
    <!-- APPLICATION PROPERTIES -->
    <!-- ====================== -->

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="19" />

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:xlargeScreens="true"/>

    <application
        android:name=".AppState"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.MyApp"
        android:hardwareAccelerated="true">


        <!-- ==================== -->
        <!-- GOOGLE PLAY SERVICES -->
        <!-- ==================== -->

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

        <!-- ================== -->
        <!-- Android Wear -->
        <!-- ================== -->

        <service
            android:name=".wear.DataLayerListenerService" >
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
            </intent-filter>
        </service>

        <!-- This is used for manual packaging I have this commented out when -->
        <!-- packaging with Android Studio-->
        <!--<meta-data android:name="com.google.android.wearable.beta.app"-->
                <!--android:resource="@xml/wearable_app_desc"/>-->

        ...The rest of the activities

    </application>

</manifest>

Handset build.gradle

buildscript {
    repositories {
        maven { url 'http://download.crashlytics.com/maven' }
    }

    dependencies {
    }
}

apply plugin: 'com.android.application'
apply plugin: 'crashlytics'
apply plugin: 'newrelic'

repositories {
    mavenCentral()
    maven { url 'http://download.crashlytics.com/maven' }
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    compile 'com.android.support:support-v4:20.0.+'
    compile 'com.android.support:appcompat-v7:20.0.+'
    compile project(':facebook')
    compile project(':mopub-sdk')
    compile project(':GooglePlay')
    compile 'com.newrelic.agent.android:android-agent:3.+'
    compile 'com.crashlytics.android:crashlytics:1.+'
    androidTestCompile fileTree(dir: 'tests/libs', include: '*.jar')
    wearApp project(':wearable')
}

android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'

    //Build type is debug to avoid conflict with Proguard
    testBuildType = "debug"

    defaultConfig {
        testApplicationId "my.package.name.test"
        testInstrumentationRunner "com.zutubi.android.junitreport.JUnitReportTestRunner"
    }

    lintOptions {
        // We do not want to abort the build due to lint errors
        abortOnError false
    }

    sourceSets {
        // Main is the default unless stated otherwise
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }
        // Testing
        androidTest.setRoot('tests')
        androidTest {
            java.srcDirs = ['tests/src']
            res.srcDirs = ['tests/res']
        }
        // Cannot add beta icons in here because custom flavour source sets are created
        // during compilation and name duplication will result in a crash
    }

    signingConfigs {
        debug {
            storeFile file("**")
            storePassword "***"
            keyAlias "***"
            keyPassword "***"
        }
        release {
            storeFile file("***")
            storePassword "***"
            keyAlias "***"
            keyPassword "***"
        }
    }

    buildTypes {
        // Development configuration
        debug {
            debuggable true
            jniDebugBuild true
            signingConfig signingConfigs.debug
            runProguard false
        }

        // Release configuration
        release {
            debuggable false
            jniDebugBuild false
            signingConfig signingConfigs.release

              // COMMENTED PROGUARD OUT FOR NOW TO SEE IF IT WILL HELP
//            // Configure ProGuard
//            runProguard true
//            // General configuration
//            proguardFile 'proguard/proguard.cfg'
//            // Add all of our component-specific configurations (excluding the Android generic, as we want it to be last)
//            FileTree tree =  fileTree(dir: 'proguard', include: '*.txt', exclude: 'Android.txt')
//            tree.each {File file ->
//                proguardFile file.getCanonicalPath()
//            }
//            // Add a fallback configuration for all Android apps
//            proguardFile 'proguard/Android.txt'
        }

        // Release configuration, but debuggable and without ProGuard
        // Used for testing features like G+ and in-app billing where a release config is required
        staging {
            debuggable true
            jniDebugBuild true
            signingConfig signingConfigs.release
            runProguard false
        }
    }

    productFlavors {
        production {
            applicationId "my.package.name"
        }
        internalBeta {
            applicationId "my.internalbetapackage.name"
            // Beta icons
            sourceSets.internalBeta.res.srcDirs = ['res-beta/internal']
        }
        externalBeta {
            applicationId "my.externalbetapackage.name"
            // Beta icons
            sourceSets.externalBeta.res.srcDirs = ['res-beta/external']
        }
        testing{
            applicationId "my.package.name"
        }
    }

    // Without this, gradle will complain that duplicate files were added to the APK, see:
    // http://***.com/questions/20673888/duplicate-files-copied-android-studio-0-4-0
    packagingOptions {
        exclude 'META-INF/LICENSE.txt' // twitter4j
        exclude 'META-INF/ASL2.0'      // jackson
        exclude 'META-INF/LICENSE'     // jackson
        exclude 'META-INF/NOTICE'      // jackson
    }

}

task makeTestApks {
    dependsOn "assembleProductionRelease"
    dependsOn "assembleProductionTest"
}

Wearable Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="my.package.name">

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault" >
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />

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

            <intent-filter>
                <action android:name="my.package.name.READ"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".wear.DataLayerListenerService" >
            <intent-filter>
                <action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
            </intent-filter>
        </service>
    </application>

</manifest>

Wearable build.gradle

repositories {
    mavenCentral()
}

apply plugin: 'com.android.application'
apply plugin: 'newrelic'

android {
    compileSdkVersion 19
    buildToolsVersion '20.0.0'
    defaultConfig {
        minSdkVersion 19
        targetSdkVersion 19
        versionCode 259
        versionName "4.6.1"
    }

    signingConfigs {
        debug {
            keyAlias '***'
            keyPassword '***'
            storeFile file('sameAsHandset/debug.keystore')
            storePassword '***'
        }
        release {
            storeFile file("sameAsHandset/android.keystore")
            storePassword "***"
            keyAlias "***"
            keyPassword "***"
        }
    }

    buildTypes {
        release {
            debuggable true
            jniDebugBuild false
            signingConfig signingConfigs.release
        }
    }

    productFlavors {
        production {
            applicationId "my.package.name"
        }
        internalBeta {
            applicationId "my.internalBetaPackage.name"
            // Beta icons
            sourceSets.internalBeta.res.srcDirs = ['res-beta/internal']
        }
        externalBeta {
            applicationId "my.externalBetaPackage.name"
            // Beta icons
            sourceSets.externalBeta.res.srcDirs = ['res-beta/external']
        }
        testing{
            applicationId "my.package.name"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile project(':GooglePlay')
    compile 'com.newrelic.agent.android:android-agent:3.+'
}

To Answer @odiggity specifically, in build.gradle file of your phone app, you should mention the exact name of the wear app folder. If you created the project in Android Studio, then your build.gradle should look like this:

                      wearApp project(':wear')

This can happen because of the following reasons:

  • Wear & Mobile app's "permissions" are not same.

This is not documented anywhere on developers website, however I found this with my personal experience. The reason I can think of behind this restriction is, Google want to prevent sneaky developers to exploit users & their privacy.

  • Package name of Wear & Mobile apps are not matching.
  • Application ID (build.gradle file) of Mobile & wear app are not matching.
  • Asset Compression

If you are using Eclipse for development, make sure you turn off the "Asset Compression" otherwise the ".apk" file in raw folder will get double compressed & the phone won't be able to recognize if the Mobile app is packaging wear app or not.

Best Solution:

Use Android Studio.

  1. Create Android Project
  2. Select Phone & Wear project
  3. Follow the steps for project creation
  4. Copy all the permissions used in Wear app to Mobile app's Manifest or vice versa