8

I want to use the PositionService of Gluon Mobile on iOS. I have written a small sample app that runs on desktop, providing (as intended) fake location changes, and on Android. On the iOS simulator, however, the listener is not called. Here is the relevant part of the code:

public class BasicView extends View {

        private static final Logger LOGGER = Logger.getLogger(BasicView.class.getName());

        final Label label;

        public BasicView(String name) {
            super(name);
            label = new Label();
            VBox controls = new VBox(15.0, label);
            controls.setAlignment(Pos.CENTER);
            setCenter(controls);
            // get current position
            Platform p = PlatformFactory.getPlatform();
            PositionService ps = p.getPositionService();
            outputPos(ps.getPosition());
            ps.positionProperty().addListener((obs, oldPos, newPos) -> {
                LOGGER.log(Level.INFO, "\nobs: {0}\noldPos: {1}\nnewPos: {2}",
                        new Object[]{obs, oldPos, newPos});
                outputPos(newPos);
            });
        }

        private void outputPos(Position p) {
            if (p != null) {
                label.setText(String.format("We are currently here: %f %f",
                        p.getLatitude(),
                        p.getLongitude()));
            }
        }

        @Override
        protected void updateAppBar(AppBar appBar) {
            appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
            appBar.setTitleText("Basic View");
            appBar.getActionItems().add(MaterialDesignIcon.SEARCH.button(e -> System.out.println("Search")));
        }

    }

I have added libCharm.a, but as far as I can tell it should not be needed here.

I also found hints on updating the info.plist as follows, but with or without it the listener is not called.

    <key>UIRequiredDeviceCapabilities</key>
    <array>
            <string>armv7</string>
            <string>location-services</string>
    </array>
    ...
    <key>NSLocationWhenInUseUsageDescription</key>
            <string>Location is required to find out where you are</string>
    <key>NSLocationAlwaysUsageDescription</key>
            <string>Location is required to find out where you are</string>

The only output regarding location I see is this:

Aug 27, 2016 1:37:31 PM com.gluonhq.charm.down.ios.IOSPositionService <init>
INFO: Location Manager configured with desiredAccuracy 10.00 and distanceFilter 100.00

Aug 27, 2016 1:37:31 PM com.gluonhq.charm.down.ios.IOSPositionService <init>
INFO: Telling LocationManager to start updating location.

I guess I am missing something here... As always, any help is greatly appreciated.

EDIT: Sorry, forgot build.gradle:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.0.8'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
    }
}

mainClassName = 'com.thomaskuenneth.gluon.positionservicedemo.PositionServiceDemo'

dependencies {
    compile 'com.gluonhq:charm:3.0.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'
}

jfxmobile {
    android {
        manifest = 'src/android/AndroidManifest.xml'
        compileSdkVersion = 23
    }
    ios {
        infoPList = file('src/ios/Default-Info.plist')
        forceLinkClasses = [
                'com.gluonhq.**.*',
                'io.datafx.**.*',
                'javax.annotations.**.*',
                'javax.inject.**.*',
                'javax.json.**.*',
                'org.glassfish.json.**.*'
        ]
    }
}
  • We have just released Charm Down 3.0.0, with a whole overhaul of the library. Have a look at the updated Gluon samples, that make use of the new 1.1.0 version of the jfxmobile plugin. Also the IDE plugins are updated to use of those versions. Give it a try and let me know if that solves your issue. – José Pereda Oct 25 '16 at 09:56
  • José, sorry for taking some time to respond. I upgraded to Gluon Mobile 4, that is, the plugin and the new Charm Down. Once I upgraded my code (using Services) and applied the changes I mentioned in my answer, I started seeing position changes in the iPad simulator. So, upgrading to Gluon Mobile 4 solved my issue. ;-) –  Oct 31 '16 at 12:39
  • Do you import `com.gluonhq.charm.down.plugins.*` (containing PositionServices)? I am compiling `com.gluonhq:charm:4.3.7` in my `build.gradle` file - but I cannot/do not know how get access to the latest Services - only see a limited amount of them. They are not possible through `import com.*.*...` (etc). – Lealo Oct 09 '17 at 23:00

1 Answers1

1

I followed the advice of José Pereda and upgraded to Gluon Mobile 4. After the following steps I saw position changes in the iPad Simulator. So, I suggest anyone having the same difficulties as I mentioned in my question, try upgrading. That solved my issue.

Update build.gradle as follows:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'org.javafxports:jfxmobile-plugin:1.1.1'
    }
}

apply plugin: 'org.javafxports.jfxmobile'

repositories {
    jcenter()
    maven {
        url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
    }
}

mainClassName = 'com.thomaskuenneth.gluon.positionservicedemo.PositionServiceDemo'

dependencies {
    compile 'com.gluonhq:charm:4.0.1'
}

jfxmobile {
    downConfig {
        version '3.0.0'
        plugins 'display', 'lifecycle', 'statusbar', 'storage', 'position'
    }
    android {
        manifest = 'src/android/AndroidManifest.xml'
        androidSdk = "/Users/thomas/Library/Android/sdk"
        compileSdkVersion = 24
    }
    ios {
        infoPList = file('src/ios/Default-Info.plist')
        forceLinkClasses = [
                'com.gluonhq.**.*',
                'io.datafx.**.*',
                'javax.annotations.**.*',
                'javax.inject.**.*',
                'javax.json.**.*',
                'org.glassfish.json.**.*'
        ]
    }
}

As Charm Down API has changed slightly, modify the code that accesses the position services as follows:

package com.thomaskuenneth.gluon.positionservicedemo;

import com.gluonhq.charm.down.Services;
import com.gluonhq.charm.down.plugins.Position;
import com.gluonhq.charm.down.plugins.PositionService;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class BasicView extends View {

    private static final Logger LOGGER = Logger.getLogger(BasicView.class.getName());

    final Label label;

    public BasicView(String name) {
        super(name);
        label = new Label();
        VBox controls = new VBox(15.0, label);
        controls.setAlignment(Pos.CENTER);
        setCenter(controls);
        Services.get(PositionService.class).ifPresent(serivce -> {
            serivce.positionProperty().addListener((obs, oldPos, newPos) -> {
                LOGGER.log(Level.INFO, "\nobs: {0}\noldPos: {1}\nnewPos: {2}",
                        new Object[]{obs, oldPos, newPos});
                outputPos(newPos);
            });
        });
    }

    private void outputPos(Position p) {
        if (p != null) {
            label.setText(String.format("We are currently here: %f %f",
                    p.getLatitude(),
                    p.getLongitude()));
        }
    }

    @Override
    protected void updateAppBar(AppBar appBar) {
        appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> System.out.println("Menu")));
        appBar.setTitleText("Basic View");
        appBar.getActionItems().add(MaterialDesignIcon.SEARCH.button(e -> System.out.println("Search")));
    }

}

In earlier versions it seemed necessary to have the file ibCharm.a in src/ios/jniLibs. With Gluon 4 I kept seeing errors upon linking until I removed the file. I assume that due to the refactoring of Charm Down that lib is no longer needed in this directory.

Also, please note that you need to edit Default-Info.plist as now mentioned in the Charm Down documentation about the PositionService. I already described this in my question. As of today, the docu does not mention to consider adding

<string>location-services</string>

to

<key>UIRequiredDeviceCapabilities</key>
<array>
    ...

but I think this might be a good idea if your app NEEDS the position service and will not run otherwise. Maybe an iOS expert could comment on this, please.

  • 1
    Looks good. About updating to Gluon Charm 4, the Gluon IDE plugin already does that, updates your build.gradle with the latest versions and the new Down plugins. You will notice that there other required plugins like `lifecycle` or `storage` that are added by default. ConfigDown will add for you the native libraries, no need to keep `libCharm.a` nor use the task `extractNativeLibrary`. – José Pereda Oct 31 '16 at 12:47
  • 1
    About `UIRequiredDeviceCapabilities`, I'm not sure if this is mandatory. In my tests, every plugin (accelerometer, camera, location, ...) works fine without adding them to that list. It seems more that `the App Store uses the contents of this key to prevent users from downloading your app onto a device that cannot possibly run it.` – José Pereda Oct 31 '16 at 12:50
  • José, I think your assumption regarding UIRequiredDeviceCapabilities is true, it is not needed to make the code work. But if an app will not work at all if location-services are not available on a device, it probably should be set. :-) Regarding the other required plugins... actually I deleted them. Would you advise me to update my answer, that is, to re-include them? –  Oct 31 '16 at 12:59
  • 1
    Yes, you should include them, as the Gluon Charm library depends on them but it doesn't include them. In your case, the `lifecycle`, if present, is used to avoid the service running when the app goes to background. – José Pereda Oct 31 '16 at 13:02
  • Done. Thanks for pointing this out and helping me improve my answer. –  Oct 31 '16 at 13:08
  • 1
    Thanks for taking the time to test it and post it, surely it will be useful to others. – José Pereda Oct 31 '16 at 13:10