4 Commits

Author SHA1 Message Date
Jose Olarte III
0bc75372b5 fix(android): target alarm broadcast to app package so receiver is triggered
Set Intent.setPackage(context.packageName) when creating PendingIntents
for AlarmManager so the broadcast is delivered to DailyNotificationReceiver
on all OEMs. Alarms were firing but the receiver was not invoked when the
component was not explicitly package-targeted.

- NotifyReceiver: setPackage on schedule, cancel, and isAlarmScheduled intents
- ReactivationManager: alarmsExist() use DailyNotificationReceiver + setPackage
- DailyNotificationScheduler: setPackage on ExactAlarmManager path intent
2026-02-05 19:28:30 +08:00
Jose Olarte III
57c7ddb7eb docs(testing): EMULATOR_GUIDE prerequisites, API 35, Apple Silicon; build.sh Android-only sync
EMULATOR_GUIDE.md:
- Add "Checking and Installing Prerequisites" (how to check Node, npm, Java,
  ANDROID_HOME, adb, emulator, AVDs; install steps; reference to
  scripts/check-environment.js)
- Use API 35 and Pixel8_API35 throughout to match project compileSdk/targetSdk
- Document arm64-v8a for Apple Silicon and x86_64 for Intel; add
  troubleshooting for "x86_64 not supported on aarch64 host"
- Bump version to 1.1.0 and last-updated date

test-apps/daily-notification-test/scripts/build.sh:
- When building only Android (--android / --run-android), run
  cap:sync:android instead of cap:sync so iOS pod install is skipped and
  Android build/run succeeds without fixing the iOS Podfile
2026-02-05 18:13:09 +08:00
Jose Olarte III
a3afefeda9 docs(testing): EMULATOR_GUIDE prerequisites and API 35
- Add "Checking and Installing Prerequisites" section:
  - How to check Node, npm, Java, ANDROID_HOME, adb, emulator, AVDs
  - Reference scripts/check-environment.js for partial check
  - Install steps for Node, Java, Android SDK (cmdline-tools only),
    sdkmanager packages, and avdmanager AVD creation
- Align SDK and AVD with project: use API 35 (android-35, build-tools 35.0.0,
  Pixel8_API35) to match compileSdk/targetSdk in variables.gradle
- Bump guide version to 1.1.0 and last-updated date
2026-02-05 17:48:46 +08:00
Jose Olarte III
d0155f0b22 docs(building): update BUILDING.md with iOS prerequisites and clean-build script
Updates BUILDING.md to reflect recent changes in build-native.sh, especially
the Xcode Command Line Tools prerequisite check and the clean-build script.

Problem:
- BUILDING.md didn't mention Xcode Command Line Tools prerequisite
  (recently added to build-native.sh)
- clean-build.sh script exists but wasn't documented
- iOS build troubleshooting lacked Command Line Tools guidance

Changes:
- Add Xcode Command Line Tools to Prerequisites section
  - Document installation command (xcode-select --install)
  - Include verification steps (xcode-select -p, xcodebuild -version)
  - Note that build script automatically checks for these tools
  - Explain that sqlite3 is part of Command Line Tools

- Document clean-build.sh script in Build Scripts section
  - Basic usage: ./scripts/clean-build.sh
  - All options: --all, --clean-gradle-cache, --clean-derived-data,
    --reinstall-node
  - Explain when to use clean builds

- Enhance iOS Native Build Process section
  - Add prerequisite note about Command Line Tools
  - Include troubleshooting commands for pod install issues
  - Reference prerequisites section for details

- Add comprehensive troubleshooting sections
  - Clean Build section at start of Troubleshooting
    - Recommends clean-build as first step for many issues
    - Lists when to use clean builds
  - iOS Build Issues section
    - Command Line Tools configuration errors
    - SQLite/linker issues and pkgx conflicts
    - CocoaPods installation problems
    - All with clear solutions and commands

The documentation now accurately reflects:
- Xcode Command Line Tools as required iOS prerequisite
- clean-build.sh as available build tool
- Complete iOS troubleshooting workflow

Files modified:
- BUILDING.md
2026-01-16 15:38:41 +08:00
7 changed files with 257 additions and 59 deletions

View File

@@ -44,9 +44,11 @@ npx cap run android
## Prerequisites
### Required Software
- **Android Studio** (latest stable version)
- **Android Studio** (latest stable version) - for Android development
- **Java 11+** (for Kotlin compilation)
- **Android SDK** with API level 21+
- **Xcode** (latest stable version) - for iOS development (macOS only)
- **Xcode Command Line Tools** - required for iOS builds (includes `xcodebuild`, `sqlite3`, etc.)
- **Node.js** 16+ (for TypeScript compilation)
- **npm** or **yarn** (for dependency management)
@@ -54,11 +56,35 @@ npx cap run android
- **Gradle Wrapper** (included in project)
- **Kotlin** (configured in build.gradle)
- **TypeScript** (for plugin interface)
- **CocoaPods** - for iOS dependency management
### iOS-Specific Prerequisites
**Xcode Command Line Tools** are required for iOS builds. The build script will verify these are installed:
```bash
# Install Xcode Command Line Tools (if not already installed)
xcode-select --install
```
**Verification:**
```bash
# Check if Command Line Tools are configured
xcode-select -p
# Verify xcodebuild is available
xcodebuild -version
# Verify sqlite3 is available (part of Command Line Tools)
sqlite3 --version
```
**Note:** The build script automatically checks for Command Line Tools and will fail with clear error messages if they're missing.
### System Requirements
- **RAM**: 4GB minimum, 8GB recommended
- **Storage**: 2GB free space
- **OS**: Windows 10+, macOS 10.14+, or Linux
- **OS**: Windows 10+, macOS 10.14+, or Linux (iOS development requires macOS)
## Build Methods
@@ -297,6 +323,8 @@ android/build/reports/tests/test/index.html
### iOS Native Build Process
**Prerequisites:** Ensure Xcode Command Line Tools are installed (see [Prerequisites](#prerequisites) section). The build script will verify this automatically.
#### 1. Navigate to iOS Directory
```bash
cd ios
@@ -307,6 +335,12 @@ cd ios
pod install
```
**Note:** If you encounter issues with `pod install`, ensure Xcode Command Line Tools are properly configured:
```bash
xcode-select --install # Install if missing
xcode-select -p # Verify installation path
```
#### 3. Build Commands
```bash
# Build using Xcode command line
@@ -782,6 +816,13 @@ The project includes several automated build scripts in the `scripts/` directory
./scripts/build-native.sh --platform ios
./scripts/build-native.sh --verbose
# Clean build (removes all build artifacts and caches)
./scripts/clean-build.sh
./scripts/clean-build.sh --all # Also cleans caches and reinstalls dependencies
./scripts/clean-build.sh --clean-gradle-cache # Clean Gradle cache
./scripts/clean-build.sh --clean-derived-data # Clean Xcode DerivedData
./scripts/clean-build.sh --reinstall-node # Reinstall node_modules
# TimeSafari-specific builds
node scripts/build-timesafari.js
@@ -948,6 +989,28 @@ adb logcat | grep DailyNotification
## Troubleshooting
### Clean Build (First Step for Many Issues)
If you encounter persistent build issues, try a clean build first:
```bash
# Clean all build artifacts (recommended first step)
./scripts/clean-build.sh
# Clean everything including caches (for stubborn issues)
./scripts/clean-build.sh --all
# Then rebuild
./scripts/build-native.sh --platform all
```
**When to use clean-build:**
- Build errors that don't make sense
- Dependency conflicts
- Stale build artifacts
- After switching branches
- After updating dependencies
### Common Issues
#### Gradle Sync Failures
@@ -1019,6 +1082,39 @@ File → Project Structure → SDK Location
# Solution: Check Kotlin version in build.gradle
```
#### iOS Build Issues
```bash
# Problem: "Xcode Command Line Tools not configured"
# Error: xcode-select -p fails or xcodebuild not found
# Solution: Install Command Line Tools
xcode-select --install
# Verify installation
xcode-select -p
xcodebuild -version
sqlite3 --version
# Problem: "sqlite3 not found" or linker errors with SQLite
# Solution: Ensure Command Line Tools are properly installed
# The build script checks for this automatically, but if you see linker errors:
xcode-select --install
# Problem: pkgx SQLite conflicts with iOS builds
# Error: Linker errors about libsqlite3.dylib
# Solution: The build script automatically handles this by unsetting problematic
# environment variables. If issues persist:
unset PKGX_DIR DYLD_LIBRARY_PATH LD_LIBRARY_PATH
./scripts/build-native.sh --platform ios
# Problem: "pod install" fails
# Solution: Ensure Command Line Tools are installed
xcode-select --install
# Then reinstall CocoaPods dependencies
cd ios
pod deintegrate
pod install
```
#### Capacitor Integration Issues
```bash
# Problem: Plugin not found in Capacitor app

View File

@@ -1,47 +1,46 @@
fix(build): add SQLite conflict detection and Command Line Tools verification
docs(building): update BUILDING.md with iOS prerequisites and clean-build script
Prevents iOS build failures caused by pkgx SQLite linking conflicts and
ensures Xcode Command Line Tools are properly installed.
Updates BUILDING.md to reflect recent changes in build-native.sh, especially
the Xcode Command Line Tools prerequisite check and the clean-build script.
Problem:
- pkgx installs SQLite built for macOS, causing linker errors when building
for iOS simulator: "linking in dylib built for 'macOS'"
- Missing Command Line Tools cause build failures without clear error messages
- BUILDING.md didn't mention Xcode Command Line Tools prerequisite
(recently added to build-native.sh)
- clean-build.sh script exists but wasn't documented
- iOS build troubleshooting lacked Command Line Tools guidance
Changes:
- Add check_sqlite_conflicts() function
- Detects pkgx SQLite installations in ~/.pkgx
- Warns about macOS dylibs that will cause iOS simulator build failures
- Checks for system SQLite from Command Line Tools
- Validates library paths (DYLD_LIBRARY_PATH, LD_LIBRARY_PATH)
- Add check_command_line_tools() function
- Verifies Xcode Command Line Tools are installed and configured
- Checks for xcodebuild availability
- Verifies sqlite3 is available (part of Command Line Tools)
- Provides clear error messages with installation instructions
- Add Xcode Command Line Tools to Prerequisites section
- Document installation command (xcode-select --install)
- Include verification steps (xcode-select -p, xcodebuild -version)
- Note that build script automatically checks for these tools
- Explain that sqlite3 is part of Command Line Tools
- Enhance pkgx detection in iOS build functions
- Specifically searches for pkgx SQLite dylibs
- Automatically removes pkgx paths from PATH environment variable
- Provides detailed warnings about detected conflicts
- Cleans all problematic environment variables before building
- Document clean-build.sh script in Build Scripts section
- Basic usage: ./scripts/clean-build.sh
- All options: --all, --clean-gradle-cache, --clean-derived-data,
--reinstall-node
- Explain when to use clean builds
- Integrate checks into environment validation
- Runs automatically when building for iOS
- Provides early warnings before build starts
- Fails fast with clear error messages if tools are missing
- Enhance iOS Native Build Process section
- Add prerequisite note about Command Line Tools
- Include troubleshooting commands for pod install issues
- Reference prerequisites section for details
This fixes the linker error:
"ld: building for 'iOS-simulator', but linking in dylib
(/Users/trent/.pkgx/sqlite.org/v3.44.2/lib/libsqlite3.0.dylib)
built for 'macOS'"
- Add comprehensive troubleshooting sections
- Clean Build section at start of Troubleshooting
- Recommends clean-build as first step for many issues
- Lists when to use clean builds
- iOS Build Issues section
- Command Line Tools configuration errors
- SQLite/linker issues and pkgx conflicts
- CocoaPods installation problems
- All with clear solutions and commands
The build script now:
- Detects pkgx SQLite conflicts before building
- Automatically fixes environment variables
- Verifies Command Line Tools are installed
- Provides clear guidance for manual fixes if needed
The documentation now accurately reflects:
- Xcode Command Line Tools as required iOS prerequisite
- clean-build.sh as available build tool
- Complete iOS troubleshooting workflow
Files modified:
- scripts/build-native.sh
- BUILDING.md

View File

@@ -154,8 +154,9 @@ public class DailyNotificationScheduler {
cancelNotification(duplicateId);
}
// Create intent for the notification
// Create intent for the notification; setPackage ensures AlarmManager delivery on all OEMs
Intent intent = new Intent(context, DailyNotificationReceiver.class);
intent.setPackage(context.getPackageName());
intent.setAction(com.timesafari.dailynotification.DailyNotificationConstants.ACTION_NOTIFICATION);
intent.putExtra(com.timesafari.dailynotification.DailyNotificationConstants.EXTRA_NOTIFICATION_ID, content.getId());

View File

@@ -147,6 +147,7 @@ class NotifyReceiver : BroadcastReceiver() {
// Strategy: Check both by scheduleId (stable) and by trigger time (catches different scheduleIds for same time)
val requestCode = getRequestCode(stableScheduleId)
val checkIntent = Intent(context, com.timesafari.dailynotification.DailyNotificationReceiver::class.java).apply {
setPackage(context.packageName)
action = "com.timesafari.daily.NOTIFICATION"
}
@@ -270,8 +271,10 @@ class NotifyReceiver : BroadcastReceiver() {
}
// FIX: Use DailyNotificationReceiver (registered in manifest) instead of NotifyReceiver
// FIX: Set action to match manifest registration
// FIX: Set action to match manifest registration; setPackage() ensures AlarmManager
// delivery reaches this app on all OEMs (see daily-notification-plugin-android-receiver-issue)
val intent = Intent(context, com.timesafari.dailynotification.DailyNotificationReceiver::class.java).apply {
setPackage(context.packageName)
action = "com.timesafari.daily.NOTIFICATION" // Must match manifest intent-filter action
putExtra("notification_id", notificationId) // DailyNotificationReceiver expects this extra
putExtra("schedule_id", stableScheduleId) // Add stable scheduleId for tracking
@@ -409,6 +412,7 @@ class NotifyReceiver : BroadcastReceiver() {
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
// FIX: Use DailyNotificationReceiver to match what was scheduled
val intent = Intent(context, com.timesafari.dailynotification.DailyNotificationReceiver::class.java).apply {
setPackage(context.packageName)
action = "com.timesafari.daily.NOTIFICATION"
}
val requestCode = when {
@@ -440,6 +444,7 @@ class NotifyReceiver : BroadcastReceiver() {
fun isAlarmScheduled(context: Context, scheduleId: String? = null, triggerAtMillis: Long? = null): Boolean {
// FIX: Use DailyNotificationReceiver to match what was scheduled
val intent = Intent(context, com.timesafari.dailynotification.DailyNotificationReceiver::class.java).apply {
setPackage(context.packageName)
action = "com.timesafari.daily.NOTIFICATION"
}
val requestCode = when {

View File

@@ -440,9 +440,9 @@ class ReactivationManager(private val context: Context) {
*/
private fun alarmsExist(): Boolean {
return try {
// Check if any PendingIntent for our receiver exists
// This is more reliable than nextAlarmClock
val intent = Intent(context, NotifyReceiver::class.java).apply {
// Check if any PendingIntent for our receiver exists (must match NotifyReceiver schedule path)
val intent = Intent(context, com.timesafari.dailynotification.DailyNotificationReceiver::class.java).apply {
setPackage(context.packageName)
action = "com.timesafari.daily.NOTIFICATION"
}
val pendingIntent = PendingIntent.getBroadcast(

View File

@@ -1,8 +1,8 @@
# Running Android App in Standalone Emulator (Without Android Studio)
**Author**: Matthew Raymer
**Last Updated**: 2025-10-12 06:50:00 UTC
**Version**: 1.0.0
**Last Updated**: 2026-02-05
**Version**: 1.1.0
## Overview
@@ -22,6 +22,81 @@ This guide demonstrates how to run the DailyNotification plugin test app in a st
- **Storage**: 2GB free space for emulator
- **OS**: Linux, macOS, or Windows with WSL
## Checking and Installing Prerequisites
### How to check
Run these in a terminal. If a command is missing or a check fails, use the install steps below.
| Requirement | How to check |
|------------------|--------------|
| **Node.js** | `node --version` (v14+ recommended; test app may require 20+) |
| **npm** | `npm --version` |
| **Java** | `java -version` (Java 11+; build scripts expect 11+) |
| **ANDROID_HOME** | `echo $ANDROID_HOME` (must be set to your Android SDK root) |
| **adb** | `adb version` (must be on PATH; usually `$ANDROID_HOME/platform-tools/adb`) |
| **emulator** | `emulator -version` (must be on PATH; usually `$ANDROID_HOME/emulator/emulator`) |
| **At least one AVD** | `emulator -list-avds` (must list at least one device name) |
**Project script:** From the repo root you can run:
```bash
node scripts/check-environment.js
```
This checks Node, npm, Java, and `ANDROID_HOME`. It does **not** check `adb`, `emulator`, or AVDs—verify those manually as above.
### How to install
- **Node.js and npm**
- Install from [nodejs.org](https://nodejs.org/) (LTS), or on macOS: `brew install node`.
- **Java (JDK 11+)**
- macOS: `brew install openjdk@17` and follow the caveats to link (e.g. `sudo ln -sfn $(brew --prefix)/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk`).
- Or install [Eclipse Temurin](https://adoptium.net/) / [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) and ensure `java` and `javac` are on your PATH.
- **Android SDK (without Android Studio)**
1. Download the [Command-line tools only](https://developer.android.com/studio#command-tools) package for your OS.
2. Create an SDK directory, e.g. `mkdir -p ~/android-sdk` and extract the zip so that you have `~/android-sdk/cmdline-tools/latest/` (the `bin` folder with `sdkmanager` and `avdmanager` must be inside `cmdline-tools/latest/`).
3. Set environment variables (add to `~/.zshrc` or `~/.bashrc`):
```bash
export ANDROID_HOME=$HOME/android-sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator
```
4. Install required SDK packages (accept licenses when prompted):
```bash
sdkmanager "platform-tools"
sdkmanager "emulator"
sdkmanager "platforms;android-35"
sdkmanager "build-tools;35.0.0"
```
Install a system image that matches your host CPU:
- **Apple Silicon (M1/M2/M3, aarch64):** `sdkmanager "system-images;android-35;google_apis;arm64-v8a"`
- **Intel Mac / Windows / Linux (x86_64):** `sdkmanager "system-images;android-35;google_apis;x86_64"`
5. Create at least one AVD (use the same image type you installed):
**Apple Silicon:**
```bash
avdmanager create avd -n Pixel8_API35 -k "system-images;android-35;google_apis;arm64-v8a" -d "pixel_8"
```
**Intel / x86_64:**
```bash
avdmanager create avd -n Pixel8_API35 -k "system-images;android-35;google_apis;x86_64" -d "pixel_8"
```
Then start the emulator with: `emulator -avd Pixel8_API35 -no-snapshot-load &` and use `adb wait-for-device` before building/installing the app.
- **Gradle**
The project uses the Gradle Wrapper (`gradlew`) inside the apps `android` directory. No separate Gradle install is needed.
After installing, run the checks again to confirm `adb`, `emulator`, and `emulator -list-avds` work.
## Step-by-Step Process
### 1. Check Available Emulators
@@ -31,21 +106,21 @@ This guide demonstrates how to run the DailyNotification plugin test app in a st
emulator -list-avds
# Example output:
# Pixel8_API34
# Pixel8_API35
```
### 2. Start the Emulator
```bash
# Start emulator in background (recommended)
emulator -avd Pixel8_API34 -no-snapshot-load &
emulator -avd Pixel8_API35 -no-snapshot-load &
# Alternative: Start in foreground
emulator -avd Pixel8_API34
emulator -avd Pixel8_API35
```
**Flags Explained:**
- `-avd Pixel8_API34` - Specifies the AVD to use
- `-avd Pixel8_API35` - Specifies the AVD to use
- `-no-snapshot-load` - Forces fresh boot (recommended for testing)
- `&` - Runs in background (optional)
@@ -141,7 +216,7 @@ adb logcat -c && adb logcat
```bash
# 1. Start emulator
emulator -avd Pixel8_API34 -no-snapshot-load &
emulator -avd Pixel8_API35 -no-snapshot-load &
# 2. Wait for emulator
adb wait-for-device
@@ -211,7 +286,17 @@ ps aux | grep emulator
pkill -f emulator
# Start with verbose logging
emulator -avd Pixel8_API34 -verbose
emulator -avd Pixel8_API35 -verbose
```
#### "x86_64 is not supported by the QEMU2 emulator on aarch64 host"
On Apple Silicon (M1/M2/M3), the emulator cannot run x86_64 system images. Use an ARM64 image and AVD instead:
```bash
sdkmanager "system-images;android-35;google_apis;arm64-v8a"
avdmanager delete avd -n Pixel8_API35 # if you already created an x86_64 AVD
avdmanager create avd -n Pixel8_API35 -k "system-images;android-35;google_apis;arm64-v8a" -d "pixel_8"
emulator -avd Pixel8_API35 -no-snapshot-load
```
#### ADB Connection Issues
@@ -256,13 +341,13 @@ cd android && ./gradlew clean
#### Emulator Performance
```bash
# Start with hardware acceleration
emulator -avd Pixel8_API34 -accel on
emulator -avd Pixel8_API35 -accel on
# Start with specific RAM allocation
emulator -avd Pixel8_API34 -memory 2048
emulator -avd Pixel8_API35 -memory 2048
# Start with GPU acceleration
emulator -avd Pixel8_API34 -gpu host
emulator -avd Pixel8_API35 -gpu host
```
#### Build Performance
@@ -336,7 +421,7 @@ adb shell am start -n com.timesafari.dailynotification/.MainActivity
### Automated Testing
```bash
# CI/CD pipeline
emulator -avd Pixel8_API34 -no-snapshot-load &
emulator -avd Pixel8_API35 -no-snapshot-load &
adb wait-for-device
./scripts/build-native.sh --platform android
cd android && ./gradlew :app:assembleDebug

View File

@@ -220,11 +220,23 @@ if ! npm run build; then
fi
log_info "Web assets built successfully"
# Step 2: Sync Capacitor
# Step 2: Sync Capacitor (Android-only when building only Android to avoid iOS pod install failure)
log_step "Syncing Capacitor with native projects..."
if ! npm run cap:sync; then
log_error "Capacitor sync failed"
exit 1
if [ "$BUILD_ALL" = true ]; then
if ! npm run cap:sync; then
log_error "Capacitor sync failed"
exit 1
fi
elif [ "$BUILD_ANDROID" = true ]; then
if ! npm run cap:sync:android; then
log_error "Capacitor sync (Android) failed"
exit 1
fi
elif [ "$BUILD_IOS" = true ]; then
if ! npm run cap:sync:ios; then
log_error "Capacitor sync (iOS) failed"
exit 1
fi
fi
log_info "Capacitor sync completed"