-1

I have two gradle product flavors: for prod and for stage server.

productFlavors {
        stage {
            // stage specific stuff
        }
        production {
            // production only
        }
    }

Also I have an AppWidget must be able only for stage now. I think I should hide my AppWidgetProvider in manifest:

<receiver
    android:name=".appwidget.AppWidgetProvider"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
       android:name="android.appwidget.provider"
       android:resource="@xml/appwidget_info" />
</receiver>

But how can I do it just for prod product flavor? Or is there another way here?

anil
  • 2,083
  • 21
  • 37
  • Are you looking for something that is related to this? http://stackoverflow.com/questions/17408480/gradle-how-to-customize-android-manifest-permissions – thekevshow Jun 19 '15 at 13:47
  • no, I'm not. put the working instructions and the bounty is yours) do not forget that I need to hide element inside tag – anil Jun 19 '15 at 13:53
  • I think I can provide you a small example which loads two separate manifests, wouldn't this be a more ideal solution? – thekevshow Jun 19 '15 at 14:17
  • Nvm I have a better solution than that, I will provide below. – thekevshow Jun 19 '15 at 14:28

3 Answers3

3

So we will have our example packages is as follows for your production and staging builds within the gradle product flavors.

productFlavors {
        production {
            packageName "x(path).x(path).gradleexample"
        }

        staging {
            packageName "x(path).x(path).gradleexample.staging"
        }
    }

Here is an example of your folder structure some of which may or may not apply to your project but should give you a run down of what is needed.

├── main
│   ├── AndroidManifest.xml
│   ├── ic_launcher-web.png
│   ├── java
│   │   └── x(path)
│   │       └── x(path)
│   │           └── gradlebuildexample
│   │               └── MainActivity.java
│   └── res
│       ├── drawable-hdpi
│       │   └── ic_launcher.png
│       ├── drawable-mdpi
│       │   └── ic_launcher.png
│       ├── drawable-xhdpi
│       │   └── ic_launcher.png
│       ├── drawable-xxhdpi
│       │   └── ic_launcher.png
│       ├── layout
│       │   └── activity_main.xml
│       ├── menu
│       │   └── main.xml
│       ├── values
│       │   ├── dimens.xml
│       │   ├── strings.xml
│       │   └── styles.xml
│       ├── values-v11
│       │   └── styles.xml
│       └── values-v14
│           └── styles.xml
├── production
│   └── java
│       └── x(path)
│           └── x(path)
│               └── gradlebuildexample
│                   └── Constants.java
└── staging
    ├── java
    │   └── x(path)
    │       └── x(path)
    │           └── gradlebuildexample
    │               └── Constants.java
    └── res
        ├── drawable-hdpi
        │   └── ic_launcher.png
        ├── drawable-mdpi
        │   └── ic_launcher.png
        ├── drawable-xhdpi
        │   └── ic_launcher.png
        ├── drawable-xxhdpi
        │   └── ic_launcher.png
        └── values
            └── string.xml

Now to be clear your string result set xml in the production and staging, among the values -> string.xml, will have to contain the following value appropriate for the manifest which will be described below.

So something like as follows

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="receiver">false</string>
</resources>

With my current understanding of your manifest it would look something like this

<receiver
    android:name=".appwidget.AppWidgetProvider"
    android:label="@string/app_name"
    android:enabled="@string/receiver">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
       android:name="android.appwidget.provider"
       android:resource="@xml/appwidget_info" />
</receiver>

So this would work, but if you saw from my third comment, a much better and simpler solution would be to have a different manifest for each build phase, because you may want more changes than just one. So below I will provide that work around as well which you can extrapolate on what I have provided.

Using source set in gradle you can specify a different build path for each manifest as follows

sourceSets {

        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            res.srcDirs = ['src/main/res']
        }

        debug {
            manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            res.srcDirs = ['src/main/debug/res']
        }

        release {
            manifest.srcFile 'src/main/release/AndroidManifest.xml'
            res.srcDirs = ['src/main/release/res']
        }
}
thekevshow
  • 774
  • 14
  • 36
3

Building on the other answer by @kev2316, here's a simpler way to accomplish that:

<meta-data
    android:name="android.appwidget.provider"
    android:resource="@xml"
    android:enabled="@bool/widget_enabled"/>

And in your build.gradle:

productFlavors {
    production {
        resValue "bool", "widget_enabled", "true"
    }
    staging {
        resValue "bool", "widget_enabled", "false"
    }
}
Simas
  • 43,548
  • 10
  • 88
  • 116
1

Ok, I tried all approaches and they all work:) I award @kev2316 with the bounty because all the ways base on his ideas.

And for future readers I want to leave some comments how I solve the problem in my project.

  1. let the AndroidManifest.xml in app/src/main stay immutable
  2. create AndroidManifest.xml in app/src/stage with this content.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="my.package" >
<application>
<!-- Declarations for the widget -->
    <receiver
        android:name=".appwidget.AppWidgetProvider"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/appwidget_info" />
    </receiver>
    <service
        android:name=".appwidget.AppWidgetRefreshService"
        android:permission="android.permission.BIND_REMOTEVIEWS"
        android:exported="false" />
</application>
</manifest>
  1. Profit! The result AndroidManifest.xml merges by gradle automatically. I have a custom Application class for the project, but it works perfect.

This approach is more common than turning off receiver with enabled option and allow to configure receiver and service as usual. Also I have to create just one additional file, so it's quite simple.

anil
  • 2,083
  • 21
  • 37