{"_id":"@brandonknudsen/admob-native-advanced","_rev":"7-c4acc8f7ff0515eb6fd14ef1fa2d905d","name":"@brandonknudsen/admob-native-advanced","dist-tags":{"latest":"1.1.2"},"versions":{"1.0.3":{"name":"@brandonknudsen/admob-native-advanced","version":"1.0.3","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.0.3","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"1a345b0fa14548e07cfc51d9656a90aa953e56c7","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.0.3.tgz","fileCount":25,"integrity":"sha512-HlXmqzCxZa9Xs+uo+L5nd+MCyIYEQP05Wy2ULFfws6ZXQS+3gtKYS//T2lvSMdIL7it/TMW6FUwcXndHbgqlZA==","signatures":[{"sig":"MEQCIBZFemo6q81u5UqmiBKbgxnPRaj1T13Jgne/axwHWLj1AiB2Bkur8HdD1NYcNzP5ByYp7nP3c7DlFlnUPHiV8VizAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53134},"main":"dist/plugin.js","types":"dist/esm/index.d.ts","module":"dist/esm/index.js","gitHead":"182f990f9bceb75f8f57c4986951aef9c0b452c8","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.0.3_1753152627693_0.48484838612191905","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@brandonknudsen/admob-native-advanced","version":"1.0.4","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.0.4","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"c0f0cdef9ff24fedef962d1976ccbbafc8fd1c1d","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.0.4.tgz","fileCount":25,"integrity":"sha512-yi175gfisWMw5D8YIw+sR4JdH1/6UYwQqO07Mfpdqa8xiNaHIX/1Q4rg5NiK2PWq2db5nWcMUxupu5U2sbjaEA==","signatures":[{"sig":"MEYCIQDchxqjUs2H2fAEvqJXMJEjeiXm3fMlSWXTYLKL36xpywIhANSjKBUGswl2ehK4fM1fvRw2bhDQo+xiFtnxoT/UyVtx","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":53129},"main":"dist/plugin.js","types":"dist/esm/index.d.ts","module":"dist/esm/index.js","gitHead":"2bc4ccd81f7b6674df28b6fdd06fe4111d885d1a","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.0.4_1753155262512_0.1901149491904217","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@brandonknudsen/admob-native-advanced","version":"1.0.5","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.0.5","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"3e7628eba5dd7be3afb1f6a993f1c07e9c7dd12a","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.0.5.tgz","fileCount":31,"integrity":"sha512-WO194cFdCiAOmKVkPA5mFBS/VNUUVMx0TruT+ieVY4rXVM/F123CMLRdsFF5Xak5NCCuCBxRsJCYNqD/9ojKSA==","signatures":[{"sig":"MEQCH2wNRumrMncAVWQKmMRhKwpP3mTKbj6/qwuJsCsyj2wCIQCcZ9JgS/f1G/6AzeBp5kNeDxy8yCMPZg7eKVM+idQ6cA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57593},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"4485530bb029b763658cc13d1fab1d1344c6f5db","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.0.5_1753159413051_0.9732643259110176","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"@brandonknudsen/admob-native-advanced","version":"1.0.6","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.0.6","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"c5e453dadb6a9bc392e2726fd7f326eb0d77a997","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.0.6.tgz","fileCount":31,"integrity":"sha512-J8c/7DEIWKpB6NLnhm6uxuucZuvXHk+wVLkq3OB29JSCjXCQlS3JKnRtTUNvLlTeZSFVjGTcgyjbxjnYEDI46w==","signatures":[{"sig":"MEQCIAMeIzXh7TGMHM1RLCdaXG86w2t0nhhHPbneWNXlTkQ7AiBrV2r3wR9wqElkr49fP6pjNfq1Q4W77Gq+nKyWEwJAzw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64291},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"b48998ead4699ccdcc775a32bb3bd065429b3c50","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.0.6_1753163532619_0.687655187128994","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@brandonknudsen/admob-native-advanced","version":"1.1.0","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.1.0","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"a25ec6e657f977ba23a2fef784b373993e10057b","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.1.0.tgz","fileCount":25,"integrity":"sha512-rtFhdd+epVoemCJgeDWLx1n2UCPqQQYExQo+Eq9D/UCL9M5mrhUqm6mArl1DR+SDQd5aFCRbAJzfqtqsxRkjRA==","signatures":[{"sig":"MEYCIQCRpRVM5X8bNe4Mk6ftp/6HtfrWwDnkPSMG9JXAqyXeiAIhAIAm2vco2pbS5GjJBoG9yD7YfQNb0ueIH587kdqLtRpf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82559},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"5d6fa147d7f62fbd9cb1ebd433cae500c5017d58","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.1.0_1753900386938_0.3515251342736594","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@brandonknudsen/admob-native-advanced","version":"1.1.1","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","_id":"@brandonknudsen/admob-native-advanced@1.1.1","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"dist":{"shasum":"d476917e36fa1c9bb5d0079534c622664dd6eea8","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.1.1.tgz","fileCount":25,"integrity":"sha512-LMLewAA25XlijJF1CWwKNVKeijyPRF+jsUDodAKW61Sa1sUhvpaNE5TQFeCPWDPaWZlm5Bl1+weoosgrhrDxGA==","signatures":[{"sig":"MEUCIA4Z6M7VN6mJ2i2PVDo8doufM1f8FzGDerauSc9Nk0dbAiEArJhee8SU+6mbQCGvHFSogdbFhJOAjdZI7QFLE0vSblE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":89430},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.js","gitHead":"5cbc00c867f402fb673355fd0b02b88807c49f19","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_npmVersion":"10.2.3","description":"Capacitor plugin for Google AdMob Native Advanced Ads","directories":{},"_nodeVersion":"18.19.0","dependencies":{"@capacitor/core":"^5.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","typescript":"^4.9.0","@capacitor/cli":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/android":"^5.0.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"_npmOperationalInternal":{"tmp":"tmp/admob-native-advanced_1.1.1_1753928356690_0.6467589338696307","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@brandonknudsen/admob-native-advanced","version":"1.1.2","description":"Capacitor plugin for Google AdMob Native Advanced Ads","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"npm run clean && tsc","clean":"rimraf ./dist","watch":"tsc --watch","prepublishOnly":"npm run build"},"keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"author":{"name":"Capacitor Community"},"license":"MIT","dependencies":{"@capacitor/core":"^5.0.0"},"devDependencies":{"@capacitor/android":"^5.0.0","@capacitor/ios":"^5.0.0","@capacitor/cli":"^5.0.0","rimraf":"^3.0.2","typescript":"^4.9.0"},"peerDependencies":{"@capacitor/core":"^5.0.0"},"capacitor":{"ios":{"src":"ios"},"android":{"src":"android"}},"_id":"@brandonknudsen/admob-native-advanced@1.1.2","gitHead":"d9cd356efdadf9a2bd27c111c9104fda4fec83b2","_nodeVersion":"18.19.0","_npmVersion":"10.2.3","dist":{"integrity":"sha512-qRn29aWjxSayQ/ufv5BRcNOaXF+DZIr5ckh03rZt27wGVaO8Dymnf25FPufpuK1bu1reWIqhDL4RGtOiGOndKw==","shasum":"d01a21758a51e020c258bcc1b5d17de884408626","tarball":"https://registry.npmjs.org/@brandonknudsen/admob-native-advanced/-/admob-native-advanced-1.1.2.tgz","fileCount":25,"unpackedSize":89109,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHNvq4pdGuZnTza4md6utv48vuSBu+n+LwmZBOusfIbmAiB2++tz+WnwxWENOpBG/W+wujqVYm0+NvxipaeibSL/KQ=="}]},"_npmUser":{"name":"brandonknudsen","email":"brandon@networkr.app"},"directories":{},"maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/admob-native-advanced_1.1.2_1753929418310_0.7394493569253162"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-22T02:50:27.621Z","modified":"2025-07-31T02:36:58.706Z","1.0.3":"2025-07-22T02:50:27.878Z","1.0.4":"2025-07-22T03:34:22.716Z","1.0.5":"2025-07-22T04:43:33.248Z","1.0.6":"2025-07-22T05:52:12.799Z","1.1.0":"2025-07-30T18:33:07.192Z","1.1.1":"2025-07-31T02:19:16.953Z","1.1.2":"2025-07-31T02:36:58.511Z"},"author":{"name":"Capacitor Community"},"license":"MIT","keywords":["capacitor","plugin","native","admob","ads","google","ionic","angular"],"description":"Capacitor plugin for Google AdMob Native Advanced Ads","maintainers":[{"name":"brandonknudsen","email":"brandon@networkr.app"}],"readme":"# Capacitor AdMob Native Advanced Plugin\n\nA Capacitor plugin for displaying Google AdMob Native Advanced Ads in Ionic and Angular applications with a **hybrid approach**: native iOS rendering for proper click tracking and JavaScript rendering for Android/web. Perfect for social media feeds and content walls.\n\n## Features\n\n- ✅ **Hybrid Rendering Approach**\n  - **iOS**: Native `GADNativeAdView` overlays with automatic click/impression tracking\n  - **Android**: JavaScript rendering with programmatic tracking\n  - **Web**: Mock data for development\n- ✅ Load Native Advanced Ads from Google AdMob\n- ✅ Extract ad assets (headline, body, images, call-to-action, etc.)\n- ✅ **iOS Native Overlays** - Seamless integration with webview positioning\n- ✅ **Custom Styling System** - Match your app's design perfectly\n- ✅ **Automatic Click Handling** - iOS SDK handles URL/app store opening\n- ✅ **Automatic Impression Tracking** - No manual reporting needed on iOS\n- ✅ Support for both app install and content ads\n- ✅ AdChoices compliance with proper positioning\n- ✅ Cross-platform (iOS & Android)\n- ✅ TypeScript support with comprehensive interfaces\n- ✅ Base64 encoded image data URLs for custom rendering\n- ✅ **Responsive Positioning** - Handles scroll, resize, and orientation changes\n\n## Why Hybrid Approach?\n\n**iOS Issue**: Google Mobile Ads SDK v11+ requires native `GADNativeAdView` components for proper click tracking and URL opening. Extracting assets to JavaScript breaks this functionality.\n\n**Our Solution**: \n- **iOS**: Load ads natively, render in `GADNativeAdView`, overlay on webview\n- **Android**: Keep existing JavaScript rendering for simplicity\n- **Result**: Native behavior on iOS, consistent experience across platforms\n\n## Installation\n\n### 1. Install the plugin\n\n```bash\nnpm install @brandonknudsen/admob-native-advanced\n```\n\n### 2. Add to your Capacitor project\n\n```bash\nnpx cap sync\n```\n\n### 3. Platform-specific setup\n\n#### Android\n\nAdd the following to your `android/app/src/main/AndroidManifest.xml`:\n\n```xml\n<application>\n    <!-- Replace with your actual AdMob app ID -->\n    <meta-data\n        android:name=\"com.google.android.gms.ads.APPLICATION_ID\"\n        android:value=\"ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy\" />\n</application>\n```\n\n#### iOS\n\nAdd the following to your `ios/App/App/Info.plist`:\n\n```xml\n<key>GADApplicationIdentifier</key>\n<string>ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy</string>\n```\n\n## Usage\n\n### 1. Initialize AdMob\n\n```typescript\nimport { AdMobNativeAdvanced } from '@brandonknudsen/admob-native-advanced';\n\n// Initialize with your AdMob app ID\nawait AdMobNativeAdvanced.initialize({\n  appId: 'ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy'\n});\n```\n\n### 2. Load a Native Ad\n\n```typescript\n// Load a native ad\nconst adData = await AdMobNativeAdvanced.loadAd({\n  adUnitId: 'ca-app-pub-xxxxxxxxxxxxxxxx/yyyyyyyyyy'\n});\n\nconsole.log('Ad loaded:', adData);\n// {\n//   adId: \"unique-ad-id\",\n//   headline: \"Amazing Product\",\n//   body: \"Discover the amazing features...\",\n//   callToAction: \"Learn More\",\n//   advertiser: \"Brand Name\",\n//   mediaContentUrl: \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n//   iconUrl: \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n//   adChoicesIconUrl: \"data:image/png;base64,iVBORw0KGgoAAAANSU...\",\n//   adChoicesText: \"AdChoices\",\n//   isAppInstallAd: false,\n//   isContentAd: true,\n//   nativeRendered: true  // iOS only\n// }\n```\n\n### 3. Create a Hybrid Angular Component\n\n```typescript\n// native-ad.component.ts\nimport { Component, Input, ViewChild, ElementRef, AfterViewInit, OnDestroy, ChangeDetectorRef } from '@angular/core';\nimport { AdMobNativeAdvanced, NativeAdData } from '@brandonknudsen/admob-native-advanced';\nimport { Capacitor } from '@capacitor/core';\n\n@Component({\n  selector: 'app-native-ad',\n  template: `\n    <div class=\"native-ad-container\" [class.ios-native]=\"isIOS\" *ngIf=\"adData\">\n      <!-- iOS: Hidden placeholder for native overlay positioning -->\n      <div \n        #adPlaceholder \n        class=\"native-ad-placeholder\"\n        [style.visibility]=\"isIOS && adData ? 'hidden' : 'visible'\">\n        \n        <!-- Android/Web: Rendered in HTML -->\n        <div class=\"native-ad\" *ngIf=\"!isIOS\" (click)=\"onAdClick()\">\n          <div class=\"ad-header\">\n            <img *ngIf=\"adData.iconUrl\" [src]=\"adData.iconUrl\" class=\"ad-icon\" alt=\"Ad icon\">\n            <div class=\"ad-info\">\n              <h3 *ngIf=\"adData.headline\" class=\"ad-headline\">{{ adData.headline }}</h3>\n              <p *ngIf=\"adData.advertiser\" class=\"ad-advertiser\">{{ adData.advertiser }}</p>\n            </div>\n            <div class=\"ad-choices\" (click)=\"onAdChoicesClick($event)\">\n              <img *ngIf=\"adData.adChoicesIconUrl\" [src]=\"adData.adChoicesIconUrl\" alt=\"AdChoices\">\n              <span>{{ adData.adChoicesText || 'AdChoices' }}</span>\n            </div>\n          </div>\n          \n          <div *ngIf=\"adData.mediaContentUrl\" class=\"ad-media\">\n            <img [src]=\"adData.mediaContentUrl\" alt=\"Ad media\">\n          </div>\n          \n          <div class=\"ad-content\">\n            <p *ngIf=\"adData.body\" class=\"ad-body\">{{ adData.body }}</p>\n            \n            <div *ngIf=\"adData.isAppInstallAd\" class=\"app-install-info\">\n              <span *ngIf=\"adData.store\" class=\"store\">{{ adData.store }}</span>\n              <span *ngIf=\"adData.price\" class=\"price\">{{ adData.price }}</span>\n              <div *ngIf=\"adData.starRating\" class=\"rating\">\n                {{ '★'.repeat(adData.starRating) }}{{ '☆'.repeat(5 - adData.starRating) }}\n              </div>\n            </div>\n          </div>\n          \n          <button *ngIf=\"adData.callToAction\" class=\"ad-cta\">\n            {{ adData.callToAction }}\n          </button>\n          \n          <div class=\"ad-label\">Ad</div>\n        </div>\n        \n        <!-- iOS: Transparent placeholder maintains layout space -->\n        <div class=\"native-ad ios-placeholder\" *ngIf=\"isIOS\" [style.height.px]=\"estimatedHeight\">\n          <!-- Native overlay will cover this -->\n        </div>\n      </div>\n    </div>\n  `,\n  styles: [`\n    .native-ad-container {\n      margin: 16px 0;\n    }\n    \n    .native-ad {\n      border: 1px solid #e0e0e0;\n      border-radius: 8px;\n      padding: 12px;\n      background: white;\n      box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n      position: relative;\n      cursor: pointer;\n    }\n    \n    .native-ad:hover {\n      box-shadow: 0 2px 8px rgba(0,0,0,0.15);\n    }\n    \n    .ad-header {\n      display: flex;\n      align-items: center;\n      margin-bottom: 12px;\n    }\n    \n    .ad-icon {\n      width: 40px;\n      height: 40px;\n      border-radius: 4px;\n      margin-right: 12px;\n      object-fit: cover;\n    }\n    \n    .ad-info {\n      flex: 1;\n    }\n    \n    .ad-headline {\n      margin: 0;\n      font-size: 16px;\n      font-weight: 600;\n      color: #333;\n      line-height: 1.3;\n    }\n    \n    .ad-advertiser {\n      margin: 4px 0 0 0;\n      font-size: 11px;\n      color: #999;\n    }\n    \n    .ad-choices {\n      display: flex;\n      align-items: center;\n      font-size: 10px;\n      color: #666;\n      cursor: pointer;\n      padding: 2px 4px;\n      border-radius: 3px;\n      background: rgba(255,255,255,0.9);\n    }\n    \n    .ad-choices img {\n      width: 16px;\n      height: 16px;\n      margin-right: 4px;\n    }\n    \n    .ad-media img {\n      width: 100%;\n      max-height: 200px;\n      object-fit: contain;\n      border-radius: 4px;\n      margin-bottom: 8px;\n    }\n    \n    .ad-body {\n      margin: 0 0 8px 0;\n      font-size: 14px;\n      line-height: 1.4;\n      color: #666;\n    }\n    \n    .app-install-info {\n      display: flex;\n      align-items: center;\n      gap: 8px;\n      margin-bottom: 8px;\n      font-size: 12px;\n    }\n    \n    .store {\n      background: #e3f2fd;\n      color: #1976d2;\n      padding: 2px 6px;\n      border-radius: 4px;\n    }\n    \n    .price {\n      color: #4caf50;\n      font-weight: bold;\n    }\n    \n    .rating {\n      color: #ff9800;\n    }\n    \n    .ad-cta {\n      width: 100%;\n      padding: 8px 16px;\n      background: #2196f3;\n      color: white;\n      border: none;\n      border-radius: 4px;\n      font-size: 14px;\n      cursor: pointer;\n      margin: 8px 0;\n    }\n    \n    .ad-cta:hover {\n      background: #1976d2;\n    }\n    \n    .ad-label {\n      position: absolute;\n      top: 8px;\n      left: 8px;\n      background: rgba(0,0,0,0.8);\n      color: white;\n      padding: 3px 8px;\n      border-radius: 3px;\n      font-size: 11px;\n      font-weight: bold;\n    }\n    \n    .ios-native .native-ad-placeholder {\n      border: none;\n      background: transparent;\n    }\n    \n    .ios-placeholder {\n      background: #f5f5f5;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      color: #999;\n      font-style: italic;\n    }\n  `]\n})\nexport class NativeAdComponent implements AfterViewInit, OnDestroy {\n  @ViewChild('adPlaceholder') adPlaceholder!: ElementRef;\n  @Input() adData!: NativeAdData;\n  \n  isIOS = Capacitor.getPlatform() === 'ios';\n  estimatedHeight = 300; // Estimated height for iOS placeholder\n  \n  private resizeObserver?: ResizeObserver;\n  private intersectionObserver?: IntersectionObserver;\n\n  constructor(private cdr: ChangeDetectorRef) {}\n\n  async ngAfterViewInit() {\n    if (this.isIOS && this.adData) {\n      await this.configureIOSNativeAd();\n      this.setupIOSPositioning();\n    } else if (this.adData) {\n      // Report impression for Android/web\n      this.reportImpression();\n    }\n  }\n\n  ngOnDestroy() {\n    if (this.isIOS && this.adData) {\n      AdMobNativeAdvanced.hideNativeAd({ adId: this.adData.adId });\n    }\n    \n    this.resizeObserver?.disconnect();\n    this.intersectionObserver?.disconnect();\n  }\n\n  private async configureIOSNativeAd() {\n    if (!this.adData) return;\n    \n    // Configure styling to match your design\n    await AdMobNativeAdvanced.configureNativeAdStyle({\n      adId: this.adData.adId,\n      style: {\n        backgroundColor: '#ffffff',\n        cornerRadius: 8,\n        borderWidth: 1,\n        borderColor: '#e0e0e0',\n        headlineColor: '#333333',\n        headlineFontSize: 16,\n        bodyColor: '#666666',\n        bodyFontSize: 14,\n        advertiserColor: '#999999',\n        advertiserFontSize: 11,\n        ctaBackgroundColor: '#2196f3',\n        ctaTextColor: '#ffffff',\n        ctaFontSize: 14\n      }\n    });\n  }\n\n  private setupIOSPositioning() {\n    if (!this.adPlaceholder || !this.adData) return;\n\n    // Initial positioning\n    this.positionNativeAd();\n\n    // Handle resize\n    this.resizeObserver = new ResizeObserver(() => {\n      this.positionNativeAd();\n    });\n    this.resizeObserver.observe(document.body);\n\n    // Handle visibility\n    this.intersectionObserver = new IntersectionObserver((entries) => {\n      entries.forEach(entry => {\n        if (this.adData) {\n          if (entry.isIntersecting) {\n            this.positionNativeAd();\n          } else {\n            AdMobNativeAdvanced.hideNativeAd({ adId: this.adData.adId });\n          }\n        }\n      });\n    }, { threshold: 0.1 });\n    \n    this.intersectionObserver.observe(this.adPlaceholder.nativeElement);\n\n    // Handle scroll with throttling\n    let ticking = false;\n    const updatePosition = () => {\n      this.positionNativeAd();\n      ticking = false;\n    };\n\n    window.addEventListener('scroll', () => {\n      if (!ticking) {\n        requestAnimationFrame(updatePosition);\n        ticking = true;\n      }\n    }, { passive: true });\n  }\n\n  private positionNativeAd() {\n    if (!this.adPlaceholder || !this.adData || !this.isIOS) return;\n\n    const rect = this.adPlaceholder.nativeElement.getBoundingClientRect();\n    const scrollY = window.pageYOffset || document.documentElement.scrollTop;\n\n    AdMobNativeAdvanced.positionNativeAd({\n      adId: this.adData.adId,\n      x: rect.left,\n      y: rect.top + scrollY,\n      width: rect.width,\n      height: rect.height\n    });\n  }\n\n  async onAdClick() {\n    if (!this.adData) return;\n    \n    // For Android, manually report click (iOS handled automatically)\n    if (!this.isIOS) {\n      try {\n        await AdMobNativeAdvanced.reportClick(this.adData.adId);\n      } catch (error) {\n        console.error('Error reporting ad click:', error);\n      }\n    }\n  }\n\n  onAdChoicesClick(event: Event) {\n    event.stopPropagation();\n    // Open AdChoices info (handled automatically on iOS)\n    if (!this.isIOS) {\n      window.open('https://www.google.com/settings/ads', '_blank');\n    }\n  }\n\n  private async reportImpression() {\n    try {\n      await AdMobNativeAdvanced.reportImpression(this.adData.adId);\n    } catch (error) {\n      console.error('Error reporting ad impression:', error);\n    }\n  }\n}\n```\n\n### 4. Use in a Social Media Feed\n\n```typescript\n// feed.component.ts\nimport { Component, OnInit } from '@angular/core';\nimport { AdMobNativeAdvanced, NativeAdData } from '@brandonknudsen/admob-native-advanced';\n\n@Component({\n  selector: 'app-feed',\n  template: `\n    <div class=\"feed\">\n      <div *ngFor=\"let item of feedItems\" class=\"feed-item\">\n        <ng-container [ngSwitch]=\"item.type\">\n          <app-post *ngSwitchCase=\"'post'\" [post]=\"item.data\"></app-post>\n          <app-native-ad *ngSwitchCase=\"'ad'\" [adData]=\"item.data\"></app-native-ad>\n        </ng-container>\n      </div>\n    </div>\n  `\n})\nexport class FeedComponent implements OnInit {\n  feedItems: Array<{ type: 'post' | 'ad', data: any }> = [];\n\n  async ngOnInit() {\n    // Initialize AdMob\n    await AdMobNativeAdvanced.initialize({\n      appId: 'ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy'\n    });\n\n    // Load your feed data\n    await this.loadFeed();\n  }\n\n  async loadFeed() {\n    // Load your posts\n    const posts = await this.getPosts();\n    \n    // Load an ad\n    const adData = await AdMobNativeAdvanced.loadAd({\n      adUnitId: 'ca-app-pub-xxxxxxxxxxxxxxxx/yyyyyyyyyy'\n    });\n\n    // Mix posts and ads (insert ad every 3-4 posts)\n    this.feedItems = [\n      { type: 'post', data: posts[0] },\n      { type: 'post', data: posts[1] },\n      { type: 'post', data: posts[2] },\n      { type: 'ad', data: adData },\n      { type: 'post', data: posts[3] },\n      // ... more items\n    ];\n  }\n\n  private async getPosts() {\n    // Your post loading logic\n    return [];\n  }\n}\n```\n\n## API Reference\n\n### Methods\n\n#### `initialize(options: InitializeOptions): Promise<void>`\n\nInitialize AdMob with your app ID.\n\n**Parameters:**\n- `options.appId` (string): Your AdMob app ID\n\n#### `loadAd(options: LoadAdOptions): Promise<NativeAdData>`\n\nLoad a native advanced ad.\n\n**Parameters:**\n- `options.adUnitId` (string): Your AdMob ad unit ID\n\n**Returns:** Promise with ad data including all available assets\n\n#### `reportClick(adId: string): Promise<void>`\n\nReport ad click to AdMob for tracking (Android only - iOS handles automatically).\n\n**Parameters:**\n- `adId` (string): The ID of the ad that was clicked\n\n#### `reportImpression(adId: string): Promise<void>`\n\nReport ad impression to AdMob for tracking (Android only - iOS handles automatically).\n\n**Parameters:**\n- `adId` (string): The ID of the ad that was shown\n\n#### `positionNativeAd(options: PositionNativeAdOptions): Promise<void>` *(iOS only)*\n\nPosition and show the native ad view overlay on iOS.\n\n**Parameters:**\n- `options.adId` (string): The ID of the ad to position\n- `options.x` (number): Screen X coordinate in pixels\n- `options.y` (number): Screen Y coordinate in pixels  \n- `options.width` (number): Width in pixels\n- `options.height` (number): Height in pixels\n\n#### `hideNativeAd(options: HideNativeAdOptions): Promise<void>` *(iOS only)*\n\nHide or remove the native ad view overlay on iOS.\n\n**Parameters:**\n- `options.adId` (string): The ID of the ad to hide\n\n#### `configureNativeAdStyle(options: ConfigureNativeAdStyleOptions): Promise<void>` *(iOS only)*\n\nConfigure the styling of the native ad view overlay on iOS.\n\n**Parameters:**\n- `options.adId` (string): The ID of the ad to style\n- `options.style` (NativeAdViewStyle): Style configuration object\n\n### Types\n\n#### `NativeAdData`\n\n```typescript\ninterface NativeAdData {\n  adId: string;                    // Unique ad identifier\n  headline?: string;               // Ad headline/title\n  body?: string;                   // Ad body text\n  callToAction?: string;           // Call-to-action text\n  advertiser?: string;             // Advertiser name\n  store?: string;                  // App store name (app install ads)\n  price?: string;                  // App price (app install ads)\n  starRating?: number;             // Star rating (app install ads)\n  mediaContentUrl?: string;        // Main ad image (base64 data URL)\n  iconUrl?: string;                // Ad icon (base64 data URL)\n  adChoicesIconUrl?: string;       // AdChoices icon (base64 data URL)\n  adChoicesText?: string;          // AdChoices text\n  isAppInstallAd?: boolean;        // Whether this is an app install ad\n  isContentAd?: boolean;           // Whether this is a content ad\n  nativeRendered?: boolean;        // Whether ad is rendered natively (iOS only)\n}\n```\n\n#### `NativeAdViewStyle` *(iOS only)*\n\n```typescript\ninterface NativeAdViewStyle {\n  backgroundColor?: string;        // Container background color (hex)\n  cornerRadius?: number;           // Border radius in pixels\n  borderWidth?: number;            // Border width in pixels\n  borderColor?: string;            // Border color (hex)\n  headlineColor?: string;          // Headline text color (hex)\n  headlineFontSize?: number;       // Headline font size in points\n  bodyColor?: string;              // Body text color (hex)\n  bodyFontSize?: number;           // Body font size in points\n  advertiserColor?: string;        // Advertiser text color (hex)\n  advertiserFontSize?: number;     // Advertiser font size in points\n  ctaBackgroundColor?: string;     // CTA button background (hex)\n  ctaTextColor?: string;           // CTA button text color (hex)\n  ctaFontSize?: number;            // CTA button font size in points\n}\n```\n\n## Event Listeners *(iOS only)*\n\n```typescript\nimport { AdMobNativeAdvanced } from '@brandonknudsen/admob-native-advanced';\n\n// Listen for ad events on iOS\nAdMobNativeAdvanced.addListener('adClicked', (data) => {\n  console.log('Ad clicked:', data.adId);\n  // Track click in analytics\n});\n\nAdMobNativeAdvanced.addListener('adImpression', (data) => {\n  console.log('Ad impression:', data.adId);\n  // Track impression in analytics\n});\n\nAdMobNativeAdvanced.addListener('adWillPresentScreen', (data) => {\n  console.log('Ad will present full screen:', data.adId);\n  // Pause video, etc.\n});\n\nAdMobNativeAdvanced.addListener('adDidDismissScreen', (data) => {\n  console.log('Ad dismissed full screen:', data.adId);\n  // Resume video, etc.\n});\n```\n\n## Test Ad Unit IDs\n\nUse these test ad unit IDs for development:\n\n- **Android/iOS Native Advanced:** `ca-app-pub-3940256099942544/2247696110`\n- **iOS Native Advanced (legacy):** `ca-app-pub-3940256099942544/3985214057`\n\n## Best Practices\n\n### 1. Platform-Specific Behavior\n- **iOS**: Let the SDK handle click/impression tracking automatically\n- **Android**: Manually report clicks and impressions\n- **Styling**: Use the styling system on iOS to match your design exactly\n\n### 2. iOS Native Ad Positioning\n- Use `getBoundingClientRect()` for accurate positioning\n- Handle scroll events with throttling (`requestAnimationFrame`)\n- Hide ads when not visible to save resources\n- Always call `hideNativeAd()` when components unmount\n\n### 3. Ad Placement\n- Place ads naturally within your content feed\n- Don't place too many ads close together\n- Insert ads every 3-4 posts for optimal user experience\n- Follow AdMob's [Native Ad Policy](https://support.google.com/admob/answer/6239795)\n\n### 4. Ad Labeling\n- Always include \"Ad\" or \"Sponsored\" label\n- Display AdChoices icon prominently (handled automatically on iOS)\n- Make it clear to users that content is promotional\n\n### 5. Error Handling\n```typescript\ntry {\n  const adData = await AdMobNativeAdvanced.loadAd({\n    adUnitId: 'your-ad-unit-id'\n  });\n  \n  // Handle successful ad load\n  if (Capacitor.getPlatform() === 'ios') {\n    // Configure iOS native styling\n    await AdMobNativeAdvanced.configureNativeAdStyle({\n      adId: adData.adId,\n      style: { /* your styling */ }\n    });\n  }\n} catch (error) {\n  console.error('Failed to load ad:', error);\n  // Handle ad load failure (e.g., show fallback content)\n}\n```\n\n### 6. Performance\n- Load ads asynchronously without blocking UI\n- Implement proper error handling for failed ad loads\n- Use intersection observers for visibility detection\n- Clean up native views on component destruction\n- Limit concurrent ad requests\n\n## Troubleshooting\n\n### Common Issues\n\n1. **\"AdMob must be initialized\" error**\n   - Ensure you call `initialize()` before `loadAd()`\n   - Check that your app ID is correct\n\n2. **\"Ad failed to load\" error**\n   - Verify your ad unit ID is correct\n   - Check your internet connection\n   - Ensure you're using test ad unit IDs during development\n\n3. **iOS: Ads not showing or clicks not working**\n   - Check that you've added the GADApplicationIdentifier to Info.plist\n   - Verify your iOS deployment target is 13.0 or higher\n   - Ensure `positionNativeAd()` is called after ad load\n   - Check that positioning coordinates are correct\n\n4. **iOS: Native overlay positioning issues**\n   - Verify `getBoundingClientRect()` returns valid dimensions\n   - Check scroll position calculations (`window.pageYOffset`)\n   - Ensure the placeholder element has proper dimensions\n\n5. **Android: Ads not showing**\n   - Check that you've added the APPLICATION_ID metadata to AndroidManifest.xml\n   - Verify your minSdkVersion is 21 or higher\n   - Ensure you're calling `reportClick()` and `reportImpression()`\n\n### Debug Mode\n\nEnable debug logging by adding this to your app initialization:\n\n```typescript\n// For development only\nif (!environment.production) {\n  // Add test device IDs to see test ads\n  console.log('Running in debug mode with test ads');\n}\n```\n\n## Migration from Previous Versions\n\nIf you're upgrading from a version without iOS native rendering:\n\n1. Update your Angular components to support the hybrid approach\n2. Add iOS-specific positioning logic\n3. Configure native ad styling for iOS\n4. Test on both platforms to ensure consistency\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Support\n\nFor support, please:\n- Open an issue on GitHub\n- Check the [AdMob documentation](https://developers.google.com/admob)\n- Review the [SETUP.md](./SETUP.md) for detailed implementation examples ","readmeFilename":"README.md"}