Using ${applicationId} in library manifest
Asked Answered
H

3

32

I'm working on an SDK that uses an internal ContentProvider, I would like to use this SDK in a few projects, and declare it in the library manifest, so I've tried this:

    <provider
        android:name=".core.MyContentProvider"
        android:authorities="${applicationId}"
        android:exported="false"/>

What happens is the ${applicationId} is replaced with the packageName of the library and not the top apk related applicationId...

Is there a way to make sure that the launching applicationId would be placed in the android:authorities value?

Hooknose answered 11/6, 2015 at 20:26 Comment(2)
I am running into the same problem. Did you find a solution?Hirudin
I didn't use any packageName in the library and the code you posted referenced the app's package name directly.Deepfreeze
S
12

Was running into the same problem with several different variants and unique IDs, and ended up going with replacing a placeholder key when Gradle is building the app, kind of like so:

Gradle 3+

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.processManifest.doLast {
            File manifestFile = file("$manifestOutputDirectory/AndroidManifest.xml")

            replaceInFile(manifestFile, 'P_AUTHORITY', variant.applicationId)
        }
    }
}

def replaceInFile(file, fromString, toString) {
    def updatedContent = file.getText('UTF-8')
            .replaceAll(fromString, toString)

    file.write(updatedContent, 'UTF-8')
}

Gradle < 3

android.applicationVariants.all { variant ->
    variant.outputs.each { output ->
        output.processManifest.doLast{
            replaceInManifest(output, 'P_AUTHORITY', variant.applicationId)
        }
    }   
}

def replaceInManifest(output, fromString, toString) {
    def manifestOutFile = output.processManifest.manifestOutputFile
    def updatedContent = manifestOutFile.getText('UTF-8').replaceAll(fromString, toString)
    manifestOutFile.write(updatedContent, 'UTF-8')
}

And then in the manifest:

<provider
    android:name=".core.MyContentProvider"
    android:authorities="P_AUTHORITY"
    android:exported="false"/>

That's come in handy quite a few times

Scruff answered 11/6, 2015 at 20:53 Comment(5)
This code must be placed in the top project Gradle file right... is there any workaround you can think of that would allow me to put this in the lib's Gradle file?Hooknose
Unfortunately I haven't yet figured out how to do that, and have just been letting the top-level build.gradle file handle it. I'm not really sure it'd be possible in the lib file, though, unless the library knew the variants / application ID for the projects they're being attached to before-hand, which is unlikely to be the case :( And yeah, it's definitely a hackier approach, but it's proven fairly useful in my use-cases. Hopefully it helps you out!Scruff
You know... I would have expected the manifest first to merge and then update the parameters... specifically the applicationId, it does not belong in any way to the library... it is only belongs to the top level project...Hooknose
I wish I knew enough about gradle to give more help, but sadly I don't yet understand it well enough to say why it would happen like thatScruff
I have successfully used this to tweak the manifest given to aapt for a android:reference attribute (which compains that dollar_openBracket_foo_closeBracket is not a valid reference). I used android.libraryVariants as it was for a lib project, and replaced "dollar_openBracket_foo_closeBracket" with some actual resource. But the most important change was to use output.processManifest.aaptFriendlyManifestOutputFile instead. Thanks for the solution basis, it could have taken me days otherwise!Blitz
N
10

You can use ${applicationId} in under manifest file. Just make sure that in your gradle file of that library doesn't have "applicationId". If you declared it in your gradle file under "defaultConfig", please remove it.

//So your gradle file of library(SDK) module looks like..

defaultConfig {
minSdkVersion Version.minSdk
targetSdkVersion Version.targetSdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} 


//And your application gradle file looks like..

defaultConfig {
    applicationId "com.example.android"
    minSdkVersion Version.minSdk
    targetSdkVersion Version.targetSdk
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 }
Nichrome answered 30/3, 2019 at 7:41 Comment(3)
This is a better solution since it solves the problem without adding additional complexity.Alliber
Not sure why, but I had the same issue as OP (and no applicationId in lib gradle file), and when I tried this again it does indeed workStanleystanly
I have this line in app/build.gradle above defaultConfig - 'namespace "com.somename"' . how does this affect package name?Fullblown
R
3

Just make it a gradle flavor variable, it will load dynamic values for different flavors. I made this for FacebookContenProvider but the same principles apply

Manifest:

<provider android:authorities="@strings/authority"
        android:name="com.facebook.FacebookContentProvider"
        android:exported="true"/>

Gradle:

productFlavors {
    flavorName {
        ...
        resValue "string", "authority", "com.facebook.app.FacebookContentProvider'YOUAPPID'"
    }
}
Refutation answered 18/3, 2022 at 14:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.