bug(geolocation): iOS requestPermissions never settles after "Allow Once" lapses, and the plugin prompts unasked
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
調査の方向性
Start in GeolocationPlugin.swift: read requestPermissions, bindAuthorisationStatusPublisher (the .notDetermined sink), and handleLocationRequest, along with the callback manager's requestPermissionsCallbacks, locationCallbacks and watchCallbacks. Reproduce on an iOS simulator by choosing "Allow Once", backgrounding the app, then calling requestPermissions again. Done means that call resolves or shows a prompt when the status is .notDetermined, and that no system prompt appears without a pending JS call.
索引モデルが issue の本文から書いたものです。
説明
Bug Report
Plugin(s)
@capacitor/geolocation 8.2.4 (iOS). The same code is in 9.0.0-next.3.
Capacitor Version
@capacitor/core and @capacitor/ios 8.5.3; iPhone 16 Pro simulator, iOS 18.3.
Platform(s)
iOS
Current Behavior
Two problems, both from how GeolocationPlugin.swift handles the .notDetermined status.
1. requestPermissions() (and getCurrentPosition()) never settle after "Allow Once" lapses.
- Call
requestPermissions()and choose Allow Once, thengetCurrentPosition(): works. - Send the app to the background (for example, open Apple Maps). About 10 seconds later iOS ends the one-time grant and the status becomes
.notDetermined. - The plugin's
authorisationStatusPublishersink sees.notDeterminedand callsrequestLocationAuthorisationby itself. The app is not in use, so locationd drops it:locationd: {"msg":"#AuthPrompt #Warning Dropping authorization request placed while insufficiently in-use", "ClientKeyPath":"i<bundle id>:", "requestType":2, "inUseLevel":0} - Back in the app, call
checkPermissions()(returnsprompt), thenrequestPermissions(). Because the status is already.notDetermined,requestPermissionsonly adds the call torequestPermissionsCallbacksand waits for the publisher. The publisher never fires again, since nothing changes, and no new authorisation request is made. The promise never resolves or rejects.getCurrentPositionparks the same way (default: breakinhandleLocationRequest), and itstimeoutdoes not help because the timer only starts inrequestSingleLocation, after authorisation.
Every later call hangs too, until the app process is restarted.
2. A permission prompt appears without any call.
Once any plugin method has been called in the process, the sink stays subscribed. Whenever the status changes to .notDetermined while the app is active, the sink requests authorisation, and the system prompt appears over whatever screen is open, with no JS call behind it:
locationd: {"msg":"Showing #AuthPrompt", "requestType":2, "Client":"i<bundle id>:"}
Expected Behavior
requestPermissions()shows the prompt (or resolves) whenever the status is.notDeterminedat the time of the call.- The plugin only asks for authorisation on behalf of a pending call.
Code Reproduction
await Geolocation.requestPermissions({ permissions: ['coarseLocation'] }); // choose "Allow Once"
await Geolocation.getCurrentPosition(); // works
// background the app for ~10 s, return
await Geolocation.checkPermissions(); // { coarseLocation: 'prompt' }
await Geolocation.requestPermissions({ permissions: ['coarseLocation'] }); // never settles
Additional Context
The patch we ship (patch-package), which fixes both cases in our testing:
@@ requestPermissions
if locationService?.authorisationStatus == .notDetermined {
shouldSetupBindings()
callbackManager?.addRequestPermissionsCallback(capacitorCall: call)
+ requestLocationAuthorisation(type: .whenInUse)
} else {
@@ bindAuthorisationStatusPublisher
case .notDetermined:
- self.requestLocationAuthorisation(type: .whenInUse)
+ if self.hasPendingCallbacks() {
+ self.requestLocationAuthorisation(type: .whenInUse)
+ }
@@ handleLocationRequest
case .restricted: callbackManager?.sendError(.permissionRestricted)
+ case .notDetermined: requestLocationAuthorisation(type: .whenInUse)
default: break
@@
+ func hasPendingCallbacks() -> Bool {
+ guard let callbackManager else { return false }
+ return !callbackManager.requestPermissionsCallbacks.isEmpty
+ || !callbackManager.locationCallbacks.isEmpty
+ || !callbackManager.watchCallbacks.isEmpty
+ }
- 主要言語
- Java
- スター
- 688
- フォーク
- 691
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 3
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
ionic-team/capacitor-plugins のほかの issue
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 80/100
ionic-team/capacitor-plugins#2627 ·
メンテナーはふだん 1 日以内に返信
-
triage
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
ionic-team/capacitor-plugins#2616 ·
メンテナーはふだん 1 日以内に返信
-
[@capacitor/app] iOS: 'Expression implicitly coerced from String? to Any' warning in getAppLanguageオープンtriage
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
ionic-team/capacitor-plugins#2604 ·
メンテナーはふだん 1 日以内に返信
-
bug(action-sheet, camera): on iPhone with Liquid Glass, action sheets show as a popover without the Cancel action対応中かも @arblitroshani が今日担当しました。 オープンplatform: ios
難易度 3/5 1〜2日 初心者へのやさしさ 20/100
ionic-team/capacitor-plugins#2630 ·
メンテナーはふだん 1 日以内に返信
-
bug(status-bar): iOS WebView moves under the status bar after a full-screen modal is dismissed対応中かも @kidzki が今日担当しました。 オープンplatform: ios
難易度 3/5 1〜2日 初心者へのやさしさ 25/100
ionic-team/capacitor-plugins#2625 ·
メンテナーはふだん 1 日以内に返信
ionic-team/capacitor-plugins の issue をすべて見る
似ている issue
-
Type: Bug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
MCP add-on: JSON responses with non-ASCII characters are truncated (wrong Content-Length)対応中かも @dhanushbs10 が今日担当しました。 オープンadd-on bug in:mcp
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
vaadin-map
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
vaadin/flow-components#10586 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 63/100
wpilibsuite/SystemcoreTesting#446 ·
メンテナーはふだん 1 日以内に返信
-
frontend quality-assurance
難易度 2/5 1〜3時間 初心者へのやさしさ 64/100
Paul-Austin-Oswego-CSC480-HCI521/gift-app#212 ·
メンテナーはふだん 1 日以内に返信