Skip to content

Commit f41745a

Browse files
Merge pull request #30 from brewkits/hotfix/ios-request-mutex-deadlock
release: v1.3.1 — iOS Hotfix & Quality Audit
2 parents 7263bc7 + 79e68c4 commit f41745a

22 files changed

Lines changed: 491 additions & 38 deletions

File tree

.github/workflows/ci-coverage.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: "Coverage Report (KMP & iOS)"
22

33
on:
44
push:
5-
branches: [ main, develop ]
5+
branches: [ "**" ]
66
pull_request:
7-
branches: [ main ]
7+
branches: [ "**" ]
88

99
jobs:
1010
coverage:

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI
22

33
on:
44
push:
5-
branches: [ "main", "feature/**" ]
5+
branches: [ "**" ]
66
pull_request:
7-
branches: [ "main" ]
7+
branches: [ "**" ]
88
workflow_dispatch:
99

1010
jobs:

.github/workflows/code-quality.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Code Quality
22

33
on:
44
push:
5-
branches: [ "main", "feature/**" ]
5+
branches: [ "**" ]
66
pull_request:
7-
branches: [ "main" ]
7+
branches: [ "**" ]
88
workflow_dispatch:
99

1010
jobs:

.github/workflows/ios.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: iOS Build
22

33
on:
44
push:
5-
branches: [ "main" ]
5+
branches: [ "**" ]
66
pull_request:
7-
branches: [ "main" ]
7+
branches: [ "**" ]
88
workflow_dispatch:
99

1010
jobs:

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
---
88

9+
## [1.3.1] - 2026-05-05
10+
11+
### 🛡️ Critical Bug Fix: iOS Deadlock
12+
- **iOS Mutex Re-entrancy Fix**: Resolved a critical deadlock in `PlatformGrantDelegate.ios.kt` where calling `request()` would hang indefinitely. This occurred because `requestInternal()` incorrectly called the public `checkStatus()` (which acquires a per-permission Mutex) while the same Mutex was already held by the parent `request()` call.
13+
- **Regression Safety**: Added `Issue29IosMutexDeadlockTest` to ensure this class of deadlock is automatically detected in the future using `withTimeout` guards.
14+
915
## [1.3.0] - 2026-04-29
1016

1117
### 🚀 Major Architectural Shift: Koin Decoupling

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ Most KMP permission libraries are simple wrappers around native APIs. Grant is a
155155
kotlin {
156156
sourceSets {
157157
commonMain.dependencies {
158-
implementation("dev.brewkits:grant-core:1.3.0")
159-
implementation("dev.brewkits:grant-compose:1.3.0") // Optional: Compose dialogs
160-
implementation("dev.brewkits:grant-core-koin:1.3.0") // Optional: Koin DI support
158+
implementation("dev.brewkits:grant-core:1.3.1")
159+
implementation("dev.brewkits:grant-compose:1.3.1") // Optional: Compose dialogs
160+
implementation("dev.brewkits:grant-core-koin:1.3.1") // Optional: Koin DI support
161161
}
162162
}
163163
}
@@ -167,7 +167,7 @@ kotlin {
167167
> For projects targeting **Web (JS)** or **Desktop (JVM)**, use an intermediate `mobileMain` source set to avoid linking iOS/Android dependencies on unsupported platforms. [Read the Guide](docs/DEPENDENCY_MANAGEMENT.md).
168168
169169
> [!NOTE]
170-
> **Koin users**: The Koin integration was moved to `grant-core-koin` in v1.3.0. Add the new artifact alongside `grant-core` and replace `GrantPlatformModule` imports. See the [Migration Guide](docs/MIGRATION_GUIDE.md).
170+
> **Koin users**: The Koin integration was moved to `grant-core-koin` in v1.3.1. Add the new artifact alongside `grant-core` and replace `GrantPlatformModule` imports. See the [Migration Guide](docs/MIGRATION_GUIDE.md).
171171
172172
---
173173

@@ -177,7 +177,7 @@ kotlin {
177177
| :--- | :--- |
178178
| [Architecture](docs/grant-core/ARCHITECTURE.md) | How concurrency, state machines, and the mutex flow work |
179179
| [iOS Setup](docs/platform-specific/ios/info-plist.md) | Critical `Info.plist` configuration — read before shipping |
180-
| [Migration Guide](docs/MIGRATION_GUIDE.md) | Upgrading from v1.2.x to v1.3.0 |
180+
| [Migration Guide](docs/MIGRATION_GUIDE.md) | Upgrading from v1.2.x to v1.3.1 |
181181
| [Service Checking](docs/grant-core/SERVICES.md) | Combining permission + hardware service checks |
182182
| [Manual Injection](docs/MANUAL_INJECTION.md) | Using Grant without any DI framework |
183183
| [Android Reliability](docs/FIX_DEAD_CLICK_ANDROID.md) | How we fix "Dead Clicks" on Android |

ROADMAP.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
11
# Grant Library — Roadmap
22

3-
> Last updated: 2026-04-30 | Current stable: **v1.3.0**
3+
> Last updated: 2026-05-05 | Current stable: **v1.3.1**
44
55
---
66

7+
## 🛠️ In Progress / Upcoming
8+
9+
### v1.4.0 (Target: Q3 2026) — Enterprise Hardening & Extensibility
10+
*Focus: Resilience against Process Death, Performance at Scale, and Architectural Purity.*
11+
12+
**1. Resilience (Android)**
13+
- [ ] **Process Death Recovery**: Implement `SavedStateHandle` support in `GrantRequestActivity`. Ensure active permission requests survive when the OS kills the app in the background.
14+
- [ ] **Activity Launch Guard**: Prevent multiple `GrantRequestActivity` instances from overlapping during rapid concurrent calls.
15+
16+
**2. Extensibility (iOS)**
17+
- [ ] **Handler Registry**: Allow developers to register custom `IosPermissionHandler` implementations for `RawPermission`. No more "Not Implemented" dead-ends on iOS.
18+
- [ ] **Modern iOS API Support**: Guidelines and helpers for `PHPicker` (no-permission photo selection) and `NSLocationTemporaryFullAccuracyUsageDescriptionKey`.
19+
20+
**3. Performance & UI**
21+
- [ ] **Parallel Status Checks**: Refactor `GrantGroupHandler` to use `async/awaitAll` for status verification, eliminating "UI Jank" when checking 10+ permissions.
22+
- [ ] **Emission Throttling**: Use `distinctUntilChanged` on internal flows to prevent redundant UI re-compositions.
23+
24+
**4. Core Architecture**
25+
- [ ] **Robust Locking**: Replace the brittle `checkStatusInternal` pattern with a cleaner internal/external separation or a re-entrant safe locking strategy.
26+
- [ ] **Atomic Store Operations**: Ensure `GrantStore` updates are atomic across all platforms to prevent race conditions during rapid state changes.
27+
728
## ✅ Released
829

30+
### v1.3.1 (2026-05-05)
31+
- HOTFIX: iOS `request()` mutex deadlock resolution (Issue #29)
32+
- Regression tests for non-reentrant mutex patterns
33+
934
### v1.3.0 (2026-04-29)
1035
- Koin decoupled into `grant-core-koin` module
1136
- `GrantAndServiceHandler` for unified permission + service flows

demo/iosApp/GrantDemo/GrantDemo.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@
360360
PRODUCT_NAME = "$(TARGET_NAME)";
361361
REGISTER_APP_GROUPS = YES;
362362
STRING_CATALOG_GENERATE_SYMBOLS = YES;
363-
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
363+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
364364
SUPPORTS_MACCATALYST = NO;
365365
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
366366
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -423,7 +423,7 @@
423423
PRODUCT_NAME = "$(TARGET_NAME)";
424424
REGISTER_APP_GROUPS = YES;
425425
STRING_CATALOG_GENERATE_SYMBOLS = YES;
426-
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
426+
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
427427
SUPPORTS_MACCATALYST = NO;
428428
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
429429
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;

docs/DEPENDENCY_MANAGEMENT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Grant library has the following dependencies:
1313
- **AndroidX Activity Compose** `1.12.1` (Android only) - For permission requests
1414

1515
### Optional Dependencies
16-
- **Koin** `4.1.1` - For dependency injection (OPTIONAL). Use `dev.brewkits:grant-core-koin:1.3.0`.
16+
- **Koin** `4.1.1` - For dependency injection (OPTIONAL). Use `dev.brewkits:grant-core-koin:1.3.1`.
1717

1818
---
1919

@@ -26,7 +26,7 @@ Grant library uses **Koin 4.1.1** for optional dependency injection support.
2626

2727
**Koin is OPTIONAL** - You don't need Koin to use Grant library!
2828

29-
As of version **1.3.0**, Koin support has been moved to a separate module to ensure `grant-core` remains a pure, dependency-free artifact.
29+
As of version **1.3.1**, Koin support has been moved to a separate module to ensure `grant-core` remains a pure, dependency-free artifact.
3030

3131
1. **Manual Creation (Recommended)** - Use `grant-core`
3232
2. **Koin DI Modules** - Use `grant-core-koin`

docs/MIGRATION_GUIDE.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Migration Guide to Grant
22

3-
**Version:** 1.3.0
3+
**Version:** 1.3.1
44
**Last Updated:** April 29, 2026
55

66
This guide helps you migrate from previous versions of Grant or other permission libraries.
@@ -9,7 +9,7 @@ This guide helps you migrate from previous versions of Grant or other permission
99

1010
## 📚 Table of Contents
1111

12-
1. [Upgrading from Grant 1.2.x to 1.3.0](#upgrading-from-grant-12x-to-130)
12+
1. [Upgrading from Grant 1.2.x to 1.3.1](#upgrading-from-grant-12x-to-130)
1313
2. [From moko-permissions](#from-moko-permissions)
1414
3. [From Google Accompanist](#from-google-accompanist)
1515
4. [From Custom Implementation](#from-custom-implementation)
@@ -19,11 +19,11 @@ This guide helps you migrate from previous versions of Grant or other permission
1919

2020
---
2121

22-
## 1️⃣ Upgrading from Grant 1.2.x to 1.3.0
22+
## 1️⃣ Upgrading from Grant 1.2.x to 1.3.1
2323

2424
### Overview
2525

26-
Version 1.3.0 is a major release focusing on architectural purity and iOS stability. The biggest change is the extraction of Koin into its own module.
26+
Version 1.3.1 is a major release focusing on architectural purity and iOS stability. The biggest change is the extraction of Koin into its own module.
2727

2828
### What Changed?
2929

@@ -34,16 +34,16 @@ Version 1.3.0 is a major release focusing on architectural purity and iOS stabil
3434
### Step-by-Step Upgrade
3535

3636
#### 1. Update Version
37-
Update your `build.gradle.kts` to version `1.3.0`.
37+
Update your `build.gradle.kts` to version `1.3.1`.
3838

3939
#### 2. Handle Koin (If you use it)
4040
If you were using `grantModule` or `grantPlatformModule`, you must now add the `grant-core-koin` dependency:
4141

4242
```kotlin
4343
// shared/build.gradle.kts
4444
commonMain.dependencies {
45-
implementation("dev.brewkits:grant-core:1.3.0")
46-
implementation("dev.brewkits:grant-core-koin:1.3.0") // New module!
45+
implementation("dev.brewkits:grant-core:1.3.1")
46+
implementation("dev.brewkits:grant-core-koin:1.3.1") // New module!
4747
}
4848
```
4949

0 commit comments

Comments
 (0)