Merge branch 'android-fixes-2026-02'
This commit is contained in:
@@ -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());
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -464,6 +467,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 {
|
||||
@@ -519,6 +523,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 {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 app’s `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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user