React Native: match multiple Maven urls to specific dependencies? - maven

Please don't mark this as duplicate. I've spent two days scouring Github, Stack, Android Studio docs, RN docs, and Gradle docs looking for an answer.
The Problem
Our React Native project won't build on Android. One build error is
Could not find com.github.wix-playground:ahbottomnavigation:2.4.9
The fix for this error is to add maven { url 'https://jitpack.io' } to the project build.gradle
After adding this, however, we get a second error, which is
Execution failed for task ':react-native-ble-plx:compileDebugJavaWithJavac'
The fix for this is adding maven { url 'https://maven.google.com' } to build.gradle
But after adding this second fix, we trigger the first error again.
The Question
Is there a way to list both maven { <url> }s in build.gradle in such a way the each maven { <url> } is used only for the specific dependency relying on it?
OR
Can we force the same support library version across all dependencies?
I have tried numerous methods from these Gradle Docs
I've tried the answer in this Stack Post
I've updated to Android Studio 3.4.1
Any help would be greatly appreciated.
Our Files
Project level build.gradle
buildscript {
repositories {
google()
mavenLocal()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
mavenLocal()
// maven { url 'https://maven.google.com' }
maven { url 'https://jitpack.io' }
maven {
url "$rootDir/../node_modules/react-native/android" // This URL still works
}
}
}
ext {
buildToolsVersion = "28.0.3"
minSdkVersion = 19
compileSdkVersion = 26
targetSdkVersion = 26
supportLibVersion = "28.0.0"
}
subprojects { subproject ->
afterEvaluate {
if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
android {
variantFilter { variant ->
def names = variant.flavors*.name
if (names.contains("reactNative51") || names.contains("reactNative56")) {
setIgnore(true)
}
}
}
}
}
}
app/build.gradle
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: "com.android.application"
apply plugin: "io.fabric"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"
repositories {
maven { url 'https://maven.fabric.io/public' }
}
import com.android.build.OutputFile
project.ext.react = [
entryFile: "index.js",
bundleInStaging: true,
devDisabledInStaging: true,
inputExcludes: ["ios/**", "__tests__/**", "bundle_out/**"]
]
apply from: "../../node_modules/react-native/react.gradle"
apply from: "../../node_modules/react-native-sentry/sentry.gradle"
def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
def debugKeystorePropertiesFile = rootProject.file("keystores/debug.keystore.properties");
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(debugKeystorePropertiesFile))
def releaseKeystorePropertiesFile = rootProject.file("keystores/release.keystore.properties");
def releaseKeystoreProperties = new Properties()
releaseKeystoreProperties.load(new FileInputStream(releaseKeystorePropertiesFile))
android {
compileSdkVersion 28
buildToolsVersion '28.0.3'
defaultConfig {
applicationId "com.example"
missingDimensionStrategy "RNN.reactNativeVersion", "reactNative55"
minSdkVersion 21
targetSdkVersion 28
versionCode 177
versionName "2.0.4"
multiDexEnabled true
ndk {
abiFilters "armeabi-v7a", "x86"
}
manifestPlaceholders = [
FABRIC_API_KEY: project.env.get("FABRIC_API_KEY"),
FABRIC_SECRET: project.env.get("FABRIC_SECRET")
]
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
signingConfigs {
debug {
storeFile file(keystoreProperties['key.store'])
storePassword keystoreProperties['key.store.password']
keyAlias keystoreProperties['key.alias']
keyPassword keystoreProperties['key.alias.password']
}
release {
storeFile file(releaseKeystoreProperties['key.store'])
storePassword releaseKeystoreProperties['key.store.password']
keyAlias releaseKeystoreProperties['key.alias']
keyPassword releaseKeystoreProperties['key.alias.password']
}
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro", "proguard-devsupport.pro"
testProguardFile 'proguard-debug.pro'
}
staging {
signingConfig signingConfigs.debug
matchingFallbacks = ['release', 'debug']
}
debug {
signingConfig signingConfigs.debug
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support' && requested.name != 'multidex') {
details.useVersion "${rootProject.ext.supportLibVersion}"
}
}
}
dependencies {
compile('com.google.android.gms:play-services-gcm:11.8.0') {
force = true
}
compile project(':react-native-push-notification')
implementation project(':react-native-awesome-card-io')
implementation project(':react-native-fabric')
implementation project(':react-native-randombytes')
implementation project(':react-native-linear-gradient')
implementation project(':react-native-spinkit')
implementation project(':react-native-keychain')
implementation project(':react-native-vector-icons')
implementation project(':react-native-ble-plx')
implementation project(':react-native-config')
implementation project(':react-native-sentry')
implementation project(':react-native-device-info')
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.0.0-alpha3'
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation "com.android.support:appcompat-v7:27.1.0"
implementation 'com.android.support:design:27.1.0'
implementation "com.facebook.react:react-native:+" // From node_modules
implementation('com.crashlytics.sdk.android:crashlytics:2.9.3#aar') {
transitive = true;
}
implementation project(':react-native-navigation')
implementation project(':react-native-tcp')
implementation 'com.android.support:design:25.4.0'
implementation "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
implementation 'com.android.support:multidex:1.0.3'
implementation ('com.github.wix-playground:ahbottomnavigation:2.4.9') {
exclude group: "com.android.support"
}
}
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- < Only if you're using GCM or localNotificationSchedule() > -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
<!-- < Only if you're using GCM or localNotificationSchedule() > -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name="android.support.multidex.MultiDexApplication"
android:label="#string/app_name"
android:icon="#mipmap/ic_launcher"
android:allowBackup="false"
android:fullBackupContent="false"
android:theme="#style/AppTheme">
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_name"
android:value="YOUR NOTIFICATION CHANNEL NAME"/>
<meta-data android:name="com.dieam.reactnativepushnotification.notification_channel_description"
android:value="YOUR NOTIFICATION CHANNEL DESCRIPTION"/>
<!-- Change the resource name to your App's accent color - or any other color you want -->
<meta-data android:name="com.dieam.reactnativepushnotification.notification_color"
android:resource="#android:color/white"/>
<!-- < Only if you're using GCM or localNotificationSchedule() > -->
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
<!-- < Only if you're using GCM or localNotificationSchedule() > -->
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
<receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
<!-- < Only if you're using GCM or localNotificationSchedule() > -->
<service
android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerServiceGcm"
android:exported="false" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="io.fabric.ApiKey"
android:value="${FABRIC_API_KEY}"
/>
<meta-data
android:name="io.fabric.ApiSecret"
android:value="${FABRIC_SECRET}"
/>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

Is there a way to list both maven { }s in build.gradle in such a way the each maven { } is used only for the specific dependency relying on it?
Matching repositories to dependencies is an incubating feature.
Currently you can check the official doc about defining multiple repo:
You can define more than one repository for resolving dependencies. Declaring multiple repositories is helpful if some dependencies are only available in one repository but not the other.
The order of declaration determines how Gradle will check for dependencies at runtime. If Gradle finds a module descriptor in a particular repository, it will attempt to download all of the artifacts for that module from the same repository. You can learn more about the inner workings of Gradle’s resolution mechanism.
Also
Can we force the same support library version across all dependencies?
You can:
Exclude the conflicted module/library from one of the dependencies
explicitly declare the support library version
ex:
ex:
implementation "your dependency:$version" {
exclude group: "org.xxxx.xxx", module: "xxxxxxx"
}
use a resolutionStragety, something like:
ex:
android {
configurations.all {
resolutionStrategy.force 'com.android.support:support-xxxx:XX.YY.ZZ'
}
}
Pay attention to this approach because you could going to force the use of a backward version in some libraries.

We used the resolution strategy (see comment above) to fix our issue. Also, in our app/build.gradle we decided against using androidx support library implementations and instead used the older com.android.support:xxx libraries. In the end the solution looked something like this.
app/build.gradle
// Force the same support library version across all dependencies
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support' && requested.name != 'multidex') {
details.useVersion "${rootProject.ext.supportLibVersion}"
}
}
}
implementation 'com.android.support:design:25.4.0'
implementation 'com.android.support:appcompatv7:${rootProject.ext.supportLibVersion}'

using this add multiple dependency at a single command
yarn add react-native-gesture-handler react-native-modal-dropdown react-native-vector-icons react-navigation
npm install --save react-native-gesture-handler react-native-modal-dropdown react-native-vector-icons react-navigation
as well use react native version wise
react-native init --version="react-native#0.36.0" MyNewApp
react-native init --version="react-native#0.59.8" MyNewAppName

Related

Android subprojects with Kotlin DSL

I'm working on migrating by Gradle build files to the Kotlin DSL and I encounter an issue.
On my parent build.gradle, I have the following piece of code
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${Version.kotlin}"
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
subprojects {
afterEvaluate { project ->
if (project.plugins.findPlugin('com.android.application') ?:
project.plugins.findPlugin('com.android.library')) {
android {
compileSdkVersion = Android.SDK_COMPILE
defaultConfig {
minSdkVersion Android.SDK_MIN
targetSdkVersion Android.SDK_TARGET
versionCode = Android.VERSION_CODE
versionName = Android.VERSION_NAME
}
...
}
}
}
}
This allows me to configure in only one place all the modules that are android applications or libraries.
However this doesn't seem to work when I migrated to kotlin:
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath(Dependency.androidGradle)
classpath(Dependency.kotlinGradle)
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
subprojects {
afterEvaluate {
if (project.plugins.findPlugin("com.android.application") != null ||
project.plugins.findPlugin("com.android.library") != null) {
android { <<<<------------ Unresolved reference: android
compileSdkVersion(Android.SDK_COMPILE)
defaultConfig {
minSdkVersion(Android.SDK_MIN)
targetSdkVersion(Android.SDK_TARGET)
versionCode = Android.VERSION_CODE
versionName = Android.VERSION_NAME
}
...
}
}
}
}
The error is Unresolved reference: android and it looks like the android{} block is not recognized by the script compiler.
My theory is that the if checking for the subproject type is not enough, and I might have to cast or get a reference to some object in which I can call the android{} block, but honestly I do not know enough.
Any clues?
Gradle Kotlin DSL determines the dependencies for each script from the gradle classpath plus the applied plugins. That's why its recommended to use the plugins { ... } block in the Kotlin DSL.
You need to add the android and kotlin plugins to your root without applying it.
plugins {
id("<android-plugin>") version "<plugin-version>" apply false
id("<kotlin-plugin>") version "<plugin-version>" apply false
}
Unfortunately, that will still not generate the static accessors for the root build script but it will give you access to the plugin classes within the script and you can reference them like:
subprojects {
// BasePlugin is the common superclass of the AppPlugin and LibraryPlugin which are the plugin classes that "com.android.application" and "com.android.library" apply
plugins.withType<BasePlugin> {
// BaseExtension is the common superclass of the AppExtension and LibraryExtension which are the extension classes registered by the two plugins to the name "android"
configure<BaseExtension> {
// This block is typed correctly
defaultConfig {
// ...
}
}
}
}

Gluon mobile cross-platform adsView

Is there any way to integrate ads such as Google's Admob library into gluon mobile on either android or iOS or hopefully both?
This is the gradle file, I have downloaded the Google Play Services library and the google Repository :
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.2.0'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'graphing.calculator.Calculator'
dependencies {
compile 'com.gluonhq:charm:4.3.0'
androidCompile 'com.google.android.gms:play-services-ads:9.4.0'
}
jfxmobile {
downConfig {
version = '3.2.0'
plugins 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
manifest = 'src/android/AndroidManifest.xml'
androidSdk = '/Users/aniket/Library/Android/sdk'
}
ios {
arch = "arm64"
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
}
}
project.afterEvaluate {
explodeAarDependencies(project.configurations.androidCompile)
}
Yes, there is a way, for both Android and iOS.
This answer already contains a snippet of how it could be done on Android. But I'll update it here using and extending the Charm Down library. I won't include the iOS solution, though, as it requires modifications in the jfxmobile plugin, as I'll explain later.
Create a new project with the Gluon plugin, and modify the following. You'll have to keep the package names I mention, but you can name your project (and package) as you want.
build.gradle script
You need to include the Google Play Services library:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.3.4'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'com.gluonhq.adview.GluonAdView' // this can be changed
dependencies {
compile 'com.gluonhq:charm:4.3.2'
androidCompile 'com.google.android.gms:play-services-ads:9.4.0'
}
jfxmobile {
downConfig {
version '3.2.4'
plugins 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
manifest = 'src/android/AndroidManifest.xml'
}
ios {
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
}
}
project.afterEvaluate {
explodeAarDependencies(project.configurations.androidCompile)
}
Note the last task: it explodes the aar files on the android/google local repositories, to extract the jars (in this case the Google Play Services jar and all its dependencies).
Note also that after modifying the build file, you need to reload the project (to sync the project and manage the new dependencies).
Source Packages/Java
Besides the project files, you need to add this package: com.gluonhq.charm.down.plugins, and these classes:
AdViewService interface
public interface AdViewService {
void setAdUnit(String unitId, String testDeviceId, boolean test);
}
AdViewServiceFactory class
public class AdViewServiceFactory extends DefaultServiceFactory<AdViewService> {
public AdViewServiceFactory() {
super(AdViewService.class);
}
}
Android/Java Packages
In the Android/Java package, add this package: com.gluonhq.charm.down.plugins.android, and this class:
AndroidAdViewService class
import android.view.Gravity;
import android.widget.LinearLayout;
import com.gluonhq.charm.down.Services;
import com.gluonhq.charm.down.plugins.LifecycleEvent;
import com.gluonhq.charm.down.plugins.LifecycleService;
import com.google.android.gms.ads.AdListener;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import javafxports.android.FXActivity;
import com.gluonhq.charm.down.plugins.AdViewService;
public class AndroidAdViewService implements AdViewService {
private AdView adView;
#Override
public void setAdUnit(String unitId, String testDeviceId, boolean test) {
FXActivity.getInstance().runOnUiThread(() -> {
LinearLayout layout = new LinearLayout(FXActivity.getInstance());
layout.setVerticalGravity(Gravity.BOTTOM);
layout.setOrientation(LinearLayout.VERTICAL);
adView = new AdView(FXActivity.getInstance());
adView.setAdSize(AdSize.SMART_BANNER);
adView.setAdUnitId(unitId);
AdRequest adRequest;
if (test) {
adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR) // All emulators
.addTestDevice(testDeviceId) // from logcat!
.build();
} else {
adRequest = new AdRequest.Builder().build();
}
adView.loadAd(adRequest);
adView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
}
});
layout.addView(adView);
FXActivity.getViewGroup().addView(layout);
});
Services.get(LifecycleService.class).ifPresent(service -> {
service.addListener(LifecycleEvent.RESUME, () -> FXActivity.getInstance().runOnUiThread(() -> adView.resume()));
service.addListener(LifecycleEvent.PAUSE, () -> FXActivity.getInstance().runOnUiThread(() -> adView.pause()));
});
}
}
It makes use of com.google.android.gms.ads.AdView. If your Android dependencies already include Google Play Services, you won't have any problem with the imports. Otherwise, go back to step 1.
Note that I'm setting a layout where the banner will go to the bottom of the screen. Change this at your convenience.
AndroidManifest.xml
You need to add this to the manifest:
<?xml version="1.0" encoding="UTF-8"?>
<manifest ...>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application ...>
<activity .../>
<meta-data android:name="com.google.android.gms.version" android:value="9452000" />
<activity android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="#android:style/Theme.Translucent"/>
</application>
</manifest>
Note the Google Play Services value corresponds with the 9.4.0 version.
Sample
Now you can add the service to your project. For that you'll need an Ad unit Id. You can create an account on Google AdMob to add your app, and get the App ID for the banner unit.
To get the test device id, you'll have to run the app first, and find in the console the id with adb logcat.
public BasicView(String name) {
super(name);
Services.get(AdViewService.class).ifPresent(ads -> {
ads.setAdUnit("ca-app-pub-17652XXXXXXXXXX/83XXXXXXXX", "0283A9A0758XXXXXXXXXXXXXXXX", true);
});
Label label = new Label("Hello JavaFX World!");
...
}
Run the sample on your Android device
You should see the ads at the bottom, and some logs at the console as well.
04-02 12:42:45.352 25520 25520 I Ads : Starting ad request.
04-02 12:42:47.844 25520 25520 I Ads : Scheduling ad refresh 60000 milliseconds from now.
04-02 12:42:47.889 25520 25520 I Ads : Ad finished loading.
iOS
For iOS it is possible as well. The problem is that it requires downloading the Google Mobile Ads SDK, and adding the GoogleMobileAds.framework to the list of frameworks, so when compiling the native code it finds it.
This should be done in the jfxmobile-plugin, so it is out of scope in this question for now.

Black screen for application build with JavafXPorts, finally it stops

I am trying to make my application run on an android device by using the jfxmobile-plugin.
Finally an
gradle androidInstall
passes throught and the apk is installed on my device.
My gradle file is this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.3.2'
}
}
apply plugin: 'org.javafxports.jfxmobile'
mainClassName = 'de.package.of.application.ClientApp'
dependencies {
compile 'com.annimon:stream:1.0.1'
compile 'com.jakewharton.threetenabp:threetenabp:1.0.4'
compile 'com.gluonhq:charm:4.2.0'
androidRuntime 'com.gluonhq:charm-android:3.0.0'
iosRuntime 'com.gluonhq:charm-ios:3.0.0'
desktopRuntime 'com.gluonhq:charm-desktop:3.0.0'
compile fileTree(dir: 'target/dependencies', include: '*.jar')
runtime fileTree(dir: 'target/dependencies', include: '*.jar')
}
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
jfxmobile {
ios {
forceLinkClasses = ['ensemble.**.*']
}
android {
//manifest = 'AndroidManifest.xml'
compileSdkVersion = '21'
androidSdk='C:/Tools/android-sdk-windows'
packagingOptions {
exclude 'META-INF/DEPENDENCIES.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
//... some more excludes
}
dexOptions {
javaMaxHeapSize '3g'
keepRuntimeAnnotatedClasses false
}
}
}
When the app is started on the device a black screen appears for some seconds and then a message pops up: 'application stopped'.
I connected to the device with
adb logcat -v threadtime
The log contains several exceptions which I will list here:
01-15 18:11:09.356 16952 16952 E dalvikvm: Unable to extract+optimize DEX from '/data/data/de.package.of.application/code_cache/secondary-dexes/de.package.of.application-1.apk.classes6.zip'
......
01-15 18:11:09.366 16952 16952 W MultiDex: Exception in makeDexElement
01-15 18:11:09.366 16952 16952 W MultiDex: java.io.IOException: unable to open DEX file
.....
01-15 18:11:09.376 16952 16952 E MultiDex: Multidex installation failure
01-15 18:11:09.376 16952 16952 E MultiDex: java.lang.NoSuchFieldException: Field dexElementsSuppressedExceptions not found in class dalvik.system.PathClassLoader
.....
java.lang.RuntimeException: Unable to instantiate application android.support.multidex.MultiDexApplication: java.lang.RuntimeException: Multi dex installation failed (Field dexElementsSuppressedExceptions not found in class dalvik.system.PathClassLoader).
...
01-15 18:11:09.386 16952 16952 E AndroidRuntime: Caused by: java.lang.RuntimeException: Multi dex installation failed (Field dexElementsSuppressedExceptions not found in class dalvik.system.PathClassLoader).
01-15 18:11:09.386 16952 16952 E AndroidRuntime: at android.support.multidex.MultiDex.install(MultiDex.java:178)
The AndroidManifest.xml is the 'default-generated by the plugin' one, which is used when no manifest-file is defined in the gradle-file (as the documentation says).
<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.package.of.application" android:versionCode="1" android:versionName="1.0">
<supports-screens android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="21"/>
<application android:label="main-client" android:name="android.support.multidex.MultiDexApplication">
<activity android:name="javafxports.android.FXActivity" android:label="main-client" android:configChanges="orientation|screenSize">
<meta-data android:name="main.class" android:value="de.package.of.application.ClientApp"/>
<meta-data android:name="debug.port" android:value="0"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
What I also tried so far:
update IDE gluon-plugin for eclipse to recent version (2.4.0)
generated a new project and compared the generated gradle-file and androidManifest.xml-file with my files from above -> I cannot see
real differences except from my additional required lines.
Does anyone have suggestions?

Gluon android notification doesn't run

How can I use android notifications in gluon?
I used the below code, but the notification doesn't run. Maybe it doesn't find LocalNotification Service?
Services.get(LocalNotificationsService.class).ifPresent(service
->
{
service.getNotifications().add(new Notification(
notificationId, "Sample Notification Text",
ZonedDateTime.now().plusSeconds(10), ()
->
{
Alert alert = new Alert(AlertType.INFORMATION,
"You have been notified!");
Platform.runLater(() -> alert.showAndWait());
}));
});
manifiest:
<activity android:name="javafxports.android.FXActivity" android:label="GluonApplication1" android:configChanges="orientation|screenSize">
<meta-data android:name="main.class" android:value="com.gluonapplication1.GluonApplication1"/>
<meta-data android:name="debug.port" android:value="0"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.gluonhq.impl.charm.down.plugins.android.NotificationActivity"
android:parentActivityName="javafxports.android.FXActivity">
<meta-data android:name="android.support.PARENT_ACTIVITY"
android:value="javafxports.android.FXActivity"/>
</activity>
<receiver android:name="com.gluonhq.impl.charm.down.plugins.android.AlarmReceiver" />
<service
android:name="com.gluonapplication1.MyIntentService"
android:exported="false">
</service>
EDIT
Dependencies included in the build.gradle file:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.gluonhq:charm:4.2.0'
compile 'com.gluonhq:charm-down-common:2.0.1'
compile group: 'com.gluonhq', name: 'charm-down-plugin-local-notifications', version: '3.1.0'
compile 'org.apache.commons:commons-lang3:3.5'
desktopRuntime 'org.xerial:sqlite-jdbc:3.15.1'
androidRuntime 'org.sqldroid:sqldroid:1.0.3'
}
Based on the list of your dependencies, you are not adding the android ones, and you are not using the new downConfig configuration to include the Charm Down plugins. Read here the changes in the build script using the jfxmobile plugin 1.1.0+.
You will need to change your build.gradle file at least to include this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.2.0'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'your.main.class.Name'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.gluonhq:charm:4.2.0'
compile 'org.apache.commons:commons-lang3:3.5'
desktopRuntime 'org.xerial:sqlite-jdbc:3.15.1'
androidRuntime 'org.sqldroid:sqldroid:1.0.3'
}
jfxmobile {
downConfig {
version = '3.1.0'
// Do not edit the line below. Use Gluon Mobile Settings in your project context menu instead
plugins 'display', 'lifecycle', 'local-notifications', 'statusbar', 'storage'
}
android {
manifest = 'src/android/AndroidManifest.xml'
}
ios {
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.gluonhq.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*'
]
}
}

how to change android app name in the build gradle file

I'm creating different flavors using gradle for 2 small android apps ,i wanna just know if i can edit app name on the xml file in the build.gradle , for my different flavors .
What do you mean by app name? the application package name in the manifest or the application name as it appears in the launcher?
If the former, do:
android {
productFlavors {
flavor1 {
packageName 'com.example.flavor1'
}
flavor2 {
packageName 'com.example.flavor2'
}
}
}
It's possible to override the app name as well but you'd have to provide a flavor overlay resource instead.
So create the following files:
src/flavor1/res/values/strings.xml
src/flavor2/res/values/strings.xml
And in them just override the string resource that contains your app name (the one that your manifest use for the main activity label through something like #string/app_name). You can also provide different translations as needed.
You can use resValue, eg.
debug {
resValue 'string', 'app_name', '"MyApp (Debug)"'`
}
release {
resValue 'string', 'app_name', '"MyApp"'
}
Make sure your AndroidManifest uses android:label="#string/app_name" for the application, and remove app_name from strings.xml as it will conflict with gradle's generated strings.xml when it tries to merge them.
Actually... For a more definitive explanation;
In main build.gradle :
ext {
APP_NAME = "My Fabulous App"
APP_NAME_DEBUG = "My Fabulous App debug"
}
In app build.gradle :
android {
buildTypes {
debug {
manifestPlaceholders = [appName: APP_NAME_DEBUG]
}
release {
manifestPlaceholders = [appName: APP_NAME]
}
}
}
so in AndroidManifest.xml
<application
...
android:label="${appName}"
>
is possible. Voilà! you have different application names for release and debug.
This answer is based on Tom's, it works the best and you can work with gradle.properties to allow further animation in build process.
In build.gradle:
debug {
resValue 'string', 'app_name', APP_NAME
}
In gradle.properties:
APP_NAME="Template 1"
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.myapp">
<application
tools:replace="android:label"
android:label="${appName}"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:label="${appName}"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Gradle
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.release
// manifestPlaceholders = [appName: appConfig.appName]
manifestPlaceholders = [appName: "Your app Name"]
}
debug {
signingConfig signingConfigs.release
// manifestPlaceholders = [appName: appConfig.appName]
manifestPlaceholders = [appName: "Your app Name"]
}
}

Resources