我刚开始使用胶子手机,我正在开发一个小型iOS应用程序。我设法使用PositionService来更新UI中标签上的用户位置。现在,即使应用程序处于后台模式,我也希望获得位置更新。由于Apple开发人员的文档,这应该通过将以下密钥添加到应用程序plist
来实现@DataJpaTest
在iPhone上部署应用程序时,只要应用程序处于活动状态,我就可以看到更新。当进入主屏幕时,更新停止并在终端(gradle - > launchIOSDevice)中消息"停止更新位置"显示。知道为什么我不能在后台模式下获得位置更新吗?
这里有相关代码:
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
以下是相关的plist条目:
Services.get(PositionService.class).ifPresent(service -> {
service.positionProperty().addListener((obs, oldPos, newPos) -> {
posLbl.setText(String.format(" %.7f %.7f\nLast update: " + LocalDateTime.now().toString(),
newPos.getLatitude(), newPos.getLongitude()));
handleData();
});
});
答案 0 :(得分:0)
可以在应用进入后台模式时找到位置服务无效的原因here:
Services.get(LifecycleService.class).ifPresent(l -> {
l.addListener(LifecycleEvent.PAUSE, IOSPositionService::stopObserver);
l.addListener(LifecycleEvent.RESUME, IOSPositionService::startObserver);
});
startObserver();
生命周期服务旨在防止在应用程序处于后台时执行不必要的操作,主要是为了节省电池。许多服务,包括位置或电池,默认使用它。
到目前为止,没有简单的方法可以删除侦听器,因为没有API可以启用或禁用它。如果您认为应该添加此内容,则可以提交问题here。
您可以使用自己的快照来分叉Charm Down存储库,删除相关代码并再次构建它,但当然这不是一个好的长期解决方案。
目前,在不修改Down的情况下,我能想到的唯一方法就是避免包含iOS的Lifecycle服务实现。
这样做,一旦您打开应用程序并实例化位置服务,startObserver
将被调用并且永不停止(直到您关闭应用程序)。
在build.gradle
文件中,不是使用downConfig
块来包含position
插件,而是在dependencies
块中执行此操作,并将遍历依赖项移除到生命周期-ios:
dependencies {
compile 'com.gluonhq:charm:4.3.7'
compile 'com.gluonhq:charm-down-plugin-position:3.6.0'
iosRuntime('com.gluonhq:charm-down-plugin-position-ios:3.6.0') {
exclude group: 'com.gluonhq', module: 'charm-down-plugin-lifecycle-ios'
}
}
jfxmobile {
downConfig {
version = '3.6.0'
plugins 'display', 'statusbar', 'storage'
}
现在将其部署到您的iOS设备,并检查位置服务是否适用于后台模式。
修改强>
正如所指出的,删除停止观察者的生命周期监听器是不够的:位置不会在后台模式下更新。
要实现此功能的解决方案,需要修改iOS的Position服务并构建本地快照。
这些步骤(仅适用于Mac):
<强> 1。克隆/分叉魅力下降
Charm Down是一个可以找到here的开源库。
<强> 2。编辑iOS的职位服务
我们需要从IOSPositionService
(link)注释掉或删除生命周期监听器:
public IOSPositionService() {
position = new ReadOnlyObjectWrapper<>();
startObserver();
}
(虽然更好的方法是添加API以允许后台模式,并根据它安装监听器。还应该要求停止观察者的方法)
现在我们必须在Position.m
(link)修改原生实现:
- (void)startObserver
{
...
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
// try to save battery by using GPS only when app is used:
[self.locationManager requestWhenInUseAuthorization];
}
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0)
{
// allow background mode
self.locationManager.allowsBackgroundLocationUpdates = YES;
}
NSLog(@"Start updating location");
...
}
(同样,这应该基于后台模式API设置)
第3。构建并安装
在Charm Down的根部,使用Mac,运行:
./gradlew clean install
(如果未安装Android sdk,可以在settings.gradle
注释掉Android服务。
这将安装Charm Down服务的快照(目前为3.7.0-SNAPSHOT)。
<强> 4。更新Gluon Mobile项目
编辑build.gradle
文件,并设置mavenLocal()
存储库和快照版本:
repositories {
mavenLocal()
jcenter()
maven {
url 'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
dependencies {
compile 'com.gluonhq:charm:4.3.7'
}
jfxmobile {
downConfig {
version = '3.7.0-SNAPSHOT'
plugins 'display', 'lifecycle', 'position', 'statusbar', 'storage'
}
保存并重新加载项目。
<强> 5。在后台模式下使用位置服务
正如评论中所指出的,当在后台模式下运行时,iOS不允许在UI中进行更改。
这意味着每当从服务中检索到新位置时,我们都必须使用缓冲区来存储它,并且只有当用户恢复应用程序时,我们才会对UI进行必要的更新。所有这些缓冲的位置。
这是一个简单的用例:使用Lifecycle服务,我们知道我们是在前台还是后台,我们只在应用程序在前台运行时更新ListView
控件(UI),或者只是恢复来自背景。
private final BooleanProperty foreground = new SimpleBooleanProperty(true);
private final Map<String, String> map = new LinkedHashMap<>();
private final ObservableList<String> positions = FXCollections.observableArrayList();
public BasicView(String name) {
super(name);
Services.get(LifecycleService.class).ifPresent(l -> {
l.addListener(LifecycleEvent.PAUSE, () -> foreground.set(false));
l.addListener(LifecycleEvent.RESUME, () -> foreground.set(true));
});
ListView<String> listView = new ListView<>(positions);
Button button = new Button("Start GPS");
button.setGraphic(new Icon(MaterialDesignIcon.GPS_FIXED));
button.setOnAction(e -> {
Services.get(PositionService.class).ifPresent(service -> {
foreground.addListener((obs, ov, nv) -> {
if (nv) {
positions.addAll(map.values());
}
});
service.positionProperty().addListener((obs, oldPos, newPos) -> {
if (foreground.get()) {
positions.add(addPosition(newPos));
} else {
map.put(LocalDateTime.now().toString(), addPosition(newPos));
}
});
});
});
VBox controls = new VBox(15.0, button, listView);
controls.setAlignment(Pos.CENTER);
setCenter(controls);
}
private String addPosition(Position position) {
return LocalDateTime.now().toString() + " :: " +
String.format("%.7f, %.7f", position.getLatitude(), position.getLongitude()) +
" :: " + (foreground.get() ? "F" : "B");
}
最后,正如OP指出的那样,确保将所需的键添加到plist:
<key>NSLocationAlwaysUsageDescription</key>
<string>A good reason.</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<string>An even better reason.</string>
<强> 6。部署并运行
允许使用位置,启动位置服务,进入后台模式时,iOS设备上的蓝色状态栏将显示该应用正在使用位置。
请注意,这可能会非常快地耗尽电池。