{"id":51377229,"url":"https://github.com/mehery-soccom/PushApp-Capacitor","last_synced_at":"2026-07-05T21:00:34.914Z","repository":{"id":329139657,"uuid":"1118291766","full_name":"mehery-soccom/PushApp-Capacitor","owner":"mehery-soccom","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-29T13:22:22.000Z","size":918,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-29T15:15:28.663Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mehery-soccom.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T14:37:57.000Z","updated_at":"2026-06-29T13:23:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mehery-soccom/PushApp-Capacitor","commit_stats":null,"previous_names":["mehery-soccom/pushapp-capacitor"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/mehery-soccom/PushApp-Capacitor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mehery-soccom%2FPushApp-Capacitor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mehery-soccom%2FPushApp-Capacitor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mehery-soccom%2FPushApp-Capacitor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mehery-soccom%2FPushApp-Capacitor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mehery-soccom","download_url":"https://codeload.github.com/mehery-soccom/PushApp-Capacitor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mehery-soccom%2FPushApp-Capacitor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35168795,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T14:00:27.947Z","updated_at":"2026-07-05T21:00:34.902Z","avatar_url":"https://github.com/mehery-soccom.png","language":"Kotlin","funding_links":[],"categories":["Third Party Components"],"sub_categories":["UI Library and Framework Ionic"],"readme":"# PushApp-Ionic SDK\n\nCapacitor 7 plugin for push notifications, in-app messaging (popup, banner, roadblock, inline, tooltip), event tracking, and session handling in Ionic/Capacitor apps (iOS + Android).\n\n**Documentation site:** [https://docs.mehery.com/guide/pushapp/ionic-sdk/](https://docs.mehery.com/guide/pushapp/ionic-sdk/) — hosted on [MeherY docs](https://docs.mehery.com/guide/pushapp/); HTML source in this repo under [`docs-site/`](docs-site/) (see [docs-site/README.md](docs-site/README.md)).\n\n## Start here\n\n| I want to… | Read this |\n|------------|-----------|\n| Integrate the SDK into my Ionic app | **[Integration Guide](docs/Integration-Guide.md)** — follow sections 1–9 in order |\n| See a working app | **`example-app/`** — copy `pushapp-setup.ts` first |\n| Look up a method | [API reference](#api-reference) below · [docs/api-reference.md](docs/api-reference.md) |\n| Test before production | [QA Test Plan](docs/QA-Test-Plan.md) |\n| Handle errors in code | [Error handling](#error-handling) below |\n\n\u003e **New to Capacitor?** Allow 2–4 hours. Test on a **real device** — push does not work in the browser.\n\n---\n\n## When to call what\n\n| When | Call | Where in your app |\n|------|------|-------------------|\n| App launches (before login screen) | `initialize()` then `register()` | `app.component.ts` or `pushapp-setup.ts` |\n| User signs in | `login()` then `saveUserData()` | Login success handler |\n| User signs out | `logout()` | Logout handler (before clearing auth) |\n| User returns with saved session | `initialize()` → `register()` → `login()` | App launch (see [Integration Guide §5C](docs/Integration-Guide.md#5c--returning-user-session-restore)) |\n| Screen opens | `setPageName()` + `sendEvent()` | Page `ionViewDidEnter` |\n| Inline campaign slot on screen | `registerPlaceholder()` / `unregisterPlaceholder()` | Page enter / leave |\n| Tooltip campaign anchor | `registerTooltipTarget()` / `unregisterTooltipTarget()` | Page enter / leave |\n\n**Lifecycle order (required):** `initialize()` → `register()` → `login()`\n\nFull code and file paths: **[Integration Guide §5](docs/Integration-Guide.md#5-sdk-integration-required)**\n\n---\n\n## Quick checklist\n\nYour app should include:\n\n- Firebase config: `android/app/google-services.json` and/or `ios/App/GoogleService-Info.plist`\n- Android Gradle: `google-services` plugin applied — see [Integration Guide §3b](docs/Integration-Guide.md#3b-android-gradle-required)\n- iOS: **Firebase/Messaging** pod, Push Notifications capability, `AppDelegate` (APNs + FCM + notification taps) — see [Integration Guide §3–4](docs/Integration-Guide.md#3-firebase-setup)\n- SDK calls in order: **`initialize()` → `register()` → `login()`** (call **`logout()`** on sign-out)\n- After login (when needed): `saveUserData()`, `setPageName()`, `sendEvent()`\n- iOS notification tap tracking — see [Integration Guide §4b](docs/Integration-Guide.md#4b-ios-notification-open--cta-tracking)\n- Inline/tooltip registration only if your PushApp campaigns use those surfaces\n\n`register()` is safe to call on every app open — the native SDK avoids duplicate registration when the device is already registered with the same push token. If the token changes later, the SDK updates it automatically after the first successful registration. After **`logout()`**, the SDK clears local registration state and registers again as a fresh guest device. Customer profiles are **not** updated automatically; call `saveUserData()` explicitly after login.\n\n---\n\n## Setup (overview)\n\nFull steps with file paths and native config: **[Integration Guide](docs/Integration-Guide.md)**\n\n1. **Install** — `npm install pushapp-ionic @capacitor/push-notifications` + `npx cap sync`\n2. **Firebase** — add config files ([Guide §3](docs/Integration-Guide.md#3-firebase-setup))\n3. **Native** — iOS `AppDelegate` + Android Gradle ([Guide §3–4](docs/Integration-Guide.md#3-firebase-setup))\n4. **App launch** — `initialize()` + `register()` ([Guide §5A–B](docs/Integration-Guide.md#5-sdk-integration-required))\n5. **After login** — `login()` + `saveUserData()` ([Guide §5C, §6](docs/Integration-Guide.md#5-sdk-integration-required))\n6. **Per screen** — `setPageName()` / `sendEvent()` ([Guide §7](docs/Integration-Guide.md#7-event-and-page-tracking))\n\n**Recommended:** copy `example-app/src/app/pushapp-setup.ts` into your project.\n\n```typescript\nimport { PushApp } from 'pushapp-ionic';\nimport { environment } from '../environments/environment';\n\nawait PushApp.initialize({\n  appId: environment.pushApp.appId,\n  pushAppId: environment.pushApp.pushAppId,\n  appSecretKey: environment.pushApp.appSecretKey,\n  sandbox: environment.pushApp.sandbox,\n  debugMode: !environment.production \u0026\u0026 environment.pushApp.debugMode,\n});\n// then register() — see pushapp-setup.ts\n```\n\n---\n\n## Configuration\n\nStore credentials in environment files — do not hardcode in components:\n\n```typescript\n// src/environments/environment.ts\nexport const environment = {\n  production: false,\n  pushApp: {\n    appId: 'yourtenant_1234567890', // channel id\n    pushAppId: 'pa_…', // PushApp API App Id\n    appSecretKey: 'pas_…', // PushApp App Secret Key\n    sandbox: true,\n    debugMode: true, // dev only — verbose native logs (tokens redacted)\n  },\n};\n```\n\nDo **not** pass `slackWebhookUrl` in production (integration debugging only).\n\n---\n\n## Environments\n\nUse the `sandbox` flag provided with your PushApp credentials:\n\n| `sandbox` | Environment |\n|-----------|-------------|\n| `false` | Production |\n| `true` | Sandbox / testing |\n\n---\n\n## Web / browser\n\n\u003e **Browser dev:** This plugin is native-only. In `ionic serve`, methods return `WEB_NOT_SUPPORTED`. Use `Capacitor.isNativePlatform()` before placeholder/tooltip calls. Test push on a **real device**.\n\n---\n\n## Inline placeholders\n\nUse when PushApp campaigns deliver **inline** content into your app UI. The SDK **automatically** tracks placeholder position on scroll, resize, and fixed headers (`ion-header`).\n\n```html\n\u003cdiv id=\"promo-banner\" class=\"promo-slot\"\u003e\u003c/div\u003e\n```\n\n```typescript\n// ionViewDidEnter\nawait PushApp.registerPlaceholder({ placeholderId: 'promo-banner' });\n\n// ionViewWillLeave\nawait PushApp.unregisterPlaceholder({ placeholderId: 'promo-banner' });\n```\n\nFull details: [Integration Guide §8](docs/Integration-Guide.md#8-optional--in-app-message-placements)\n\n---\n\n## Tooltip targets\n\nRegister anchor elements for native tooltips. Register in `ionViewDidEnter` after DOM layout (`requestAnimationFrame` / short `setTimeout`). `targetId` must match your PushApp campaign config.\n\n```typescript\nconst el = document.getElementById('deals-fab');\nconst rect = el!.getBoundingClientRect();\n\nawait PushApp.registerTooltipTarget({\n  targetId: 'center', // campaign target id\n  x: Math.round(rect.left),\n  y: Math.round(rect.top),\n  width: Math.round(rect.width),\n  height: Math.round(rect.height),\n});\n\nawait PushApp.unregisterTooltipTarget({ targetId: 'center' });\n```\n\nFull details: [Integration Guide §8](docs/Integration-Guide.md#tooltip-target)\n\n---\n\n## API reference\n\n### Core\n\n| Method | When to call |\n|--------|----------------|\n| `initialize({ appId, pushAppId, appSecretKey, sandbox?, debugMode?, slackWebhookUrl? })` | App startup |\n| `register({ fcmToken?, apnsToken?, token? })` | After initialize — **both platforms**; pass empty `fcmToken` to use native cached tokens (recommended — see `pushapp-setup.ts`) |\n| `login({ userId })` | After register, when user signs in |\n| `logout()` | On sign-out — clears local session and delinks device on server |\n| `saveUserData({ code, additionalInfo, cohorts })` | After login |\n| `setPageName({ pageName })` | On screen change |\n| `sendEvent({ eventName, eventData })` | On user actions |\n| `getDeviceHeaders()` | Anytime |\n| `trackPushNotificationEvent({ token, event, ctaId? })` | Notification open / CTA tap¹ |\n\n¹ Requires native notification handler — see [Integration Guide §4b](docs/Integration-Guide.md#4b-ios-notification-open--cta-tracking). Android handles taps via the SDK's `NotificationClickReceiver`.\n\n### Inline \u0026 tooltip\n\n| Method | When to call |\n|--------|----------------|\n| `registerPlaceholder({ placeholderId, elementId?, clipTopSelector? })` | View enter |\n| `unregisterPlaceholder({ placeholderId })` | View leave |\n| `registerTooltipTarget({ targetId, x, y, width, height })` | View enter |\n| `unregisterTooltipTarget({ targetId })` | View leave |\n\nAuto-generated details: run `npm run docgen` → [docs/api-reference.md](docs/api-reference.md)\n\n---\n\n## Error handling\n\nNative methods reject with stable `code` values (e.g. `NOT_INITIALIZED`, `REGISTER_FAILED`, `EMPTY_TOKEN`). Import helpers from the package:\n\n```typescript\nimport { PushApp, PushAppErrorCode, getPushAppErrorCode, isPushAppError } from 'pushapp-ionic';\n\ntry {\n  await PushApp.register({ fcmToken: '' });\n} catch (err) {\n  if (getPushAppErrorCode(err) === PushAppErrorCode.EMPTY_TOKEN) {\n    // retry when token arrives — see pushapp-setup.ts\n  }\n}\n```\n\nCommon codes: [Integration Guide §13](docs/Integration-Guide.md#13-error-handling)\n\n---\n\n## Platform notes\n\n### Android\n\n- Minimum API 23 (Android 6.0)\n- Android 13+: notification permission is requested by the SDK on `initialize()` — user must tap **Allow**\n- ProGuard (release): add to `android/app/proguard-rules.pro`:\n\n  ```\n  -keep class com.mehery.pushapp.** { *; }\n  ```\n\n- Gradle: `google-services` plugin required — see [Integration Guide §3b](docs/Integration-Guide.md#3b-android-gradle-required)\n\n### iOS\n\n- Minimum iOS **15.2** (match `platform :ios` in `Podfile`)\n- Enable **Push Notifications** capability in Xcode\n- Add **`pod 'Firebase/Messaging'`** to `ios/App/Podfile`, then `pod install`\n- `AppDelegate`: Firebase init, forward APNs token to Firebase + PushApp, handle FCM refresh, notification tap tracking — see [Integration Guide §4](docs/Integration-Guide.md#4-ios-native-setup)\n- Reference: `example-app/ios/App/App/AppDelegate.swift`\n\n---\n\n## Example app\n\nRun the demo:\n\n```bash\ncd example-app \u0026\u0026 npm install \u0026\u0026 npx cap sync\n```\n\n| File | What to copy |\n|------|----------------|\n| `src/app/pushapp-setup.ts` | `initialize` + `register` with retry |\n| `src/app/login/login.page.ts` | `login` + `saveUserData` |\n| `src/app/home/home.page.ts` | `setPageName`, placeholders, tooltips, `logout` |\n| `ios/App/App/AppDelegate.swift` | Firebase + APNs + FCM refresh + notification tap tracking |\n\nThis is the **canonical integration pattern** — prefer it over ad-hoc snippets.\n\n---\n\n## Troubleshooting\n\n| Issue | What to check |\n|-------|----------------|\n| `initialize` fails | App ID format: `tenant_suffix` (e.g. `demo_1763369170735`) |\n| `register` rejected | Call `initialize()` first; token may not be ready on first launch — use retry pattern from `pushapp-setup.ts` |\n| Token refresh / new FCM | Handled natively after first successful register (update API, not register) — no extra JS needed |\n| `login` rejected | Call `register()` successfully first |\n| No push on device | Real device required; verify Firebase config, Gradle plugin, and notification permissions |\n| Testing in browser | Expected: `WEB_NOT_SUPPORTED` — use a device |\n| After logout, push tied to old user | Call `logout()` before clearing local auth |\n| Inline never shows | `placeholderId` mismatch; register after DOM ready; call `setPageName` / `sendEvent` |\n| Inline overlaps header | Ensure `clipTopSelector` matches your fixed header (default: `ion-header`) |\n| Parse errors in catch | Use `getPushAppErrorCode(err)` instead of parsing message strings |\n\n**Logs:** Android Logcat / iOS Xcode console → filter `PushApp` (use `PushApp:D` on Android for debug logs)\n\n---\n\n## Development (SDK maintainers)\n\n```bash\nnpm install\nnpm run lint      # ESLint + Prettier + SwiftLint\nnpm run build\nnpm test          # TypeScript unit tests (Node 18+)\nnpm run test:contract  # verify error codes match across TS / Kotlin / Swift\nnpm run verify    # build + Android tests + SwiftLint\n```\n\nCI: [`.github/workflows/ci.yml`](.github/workflows/ci.yml) · Release: [CHANGELOG.md](CHANGELOG.md) · [docs/RELEASE.md](docs/RELEASE.md)\n\n---\n\n## Version\n\nCurrent version: `0.1.2` — see [CHANGELOG.md](CHANGELOG.md) and [docs/RELEASE.md](docs/RELEASE.md).\n\n---\n\n## Support\n\n- [GitHub Issues](https://github.com/mehery-soccom/PushApp-Capacitor/issues)\n- [Integration Guide](docs/Integration-Guide.md) — step-by-step setup\n- [API reference](docs/api-reference.md) — run `npm run docgen` to refresh from TypeScript\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmehery-soccom%2FPushApp-Capacitor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmehery-soccom%2FPushApp-Capacitor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmehery-soccom%2FPushApp-Capacitor/lists"}