{"id":43790938,"url":"https://github.com/hyodotdev/openiap-google","last_synced_at":"2026-02-05T20:17:54.813Z","repository":{"id":314191978,"uuid":"1048754964","full_name":"hyodotdev/openiap-google","owner":"hyodotdev","description":"In-App Purchase in Google mobile platform that confirms OpenIAP","archived":false,"fork":false,"pushed_at":"2025-10-16T13:37:13.000Z","size":1190,"stargazers_count":7,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-16T22:28:49.615Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/hyodotdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-02T01:20:21.000Z","updated_at":"2025-10-16T13:37:17.000Z","dependencies_parsed_at":"2025-10-16T18:51:18.682Z","dependency_job_id":"a00c19e1-3879-45f6-8474-d382f22b3b41","html_url":"https://github.com/hyodotdev/openiap-google","commit_stats":null,"previous_names":["hyodotdev/openiap-google"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/hyodotdev/openiap-google","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyodotdev%2Fopeniap-google","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyodotdev%2Fopeniap-google/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyodotdev%2Fopeniap-google/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyodotdev%2Fopeniap-google/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyodotdev","download_url":"https://codeload.github.com/hyodotdev/openiap-google/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyodotdev%2Fopeniap-google/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29133378,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T19:36:52.185Z","status":"ssl_error","status_checked_at":"2026-02-05T19:35:40.941Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-02-05T20:17:54.021Z","updated_at":"2026-02-05T20:17:54.802Z","avatar_url":"https://github.com/hyodotdev.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenIAP Android\n\n\u003e [!WARNING]\n\u003e\n\u003e ## ⚠️ DEPRECATED - Repository Moved\n\u003e\n\u003e **This repository has been deprecated and is no longer maintained.**\n\u003e\n\u003e The OpenIAP Android implementation has been moved to the official monorepo:\n\u003e\n\u003e ### 👉 **[https://github.com/hyodotdev/openiap](https://github.com/hyodotdev/openiap)**\n\u003e\n\u003e Please update your bookmarks and use the monorepo for:\n\u003e\n\u003e - Latest updates and releases\n\u003e - Bug reports and issues\n\u003e - Feature requests\n\u003e - Contributing\n\u003e\n\u003e All future development will happen in the monorepo. This repository will remain available for historical reference only.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"./logo.png\" alt=\"OpenIAP Google Logo\" width=\"120\" height=\"120\"\u003e\n\n  \u003cp\u003e\u003cstrong\u003eAndroid implementation of the \u003ca href=\"https://www.openiap.dev/\"\u003eOpenIAP\u003c/a\u003e specification using Google Play Billing.\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.hyochan.openiap/openiap-google)](https://central.sonatype.com/artifact/io.github.hyochan.openiap/openiap-google)\n[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)\n[![Publish to Maven Central](https://github.com/hyodotdev/openiap-google/actions/workflows/publish.yml/badge.svg)](https://github.com/hyodotdev/openiap-google/actions/workflows/publish.yml)\n[![CI](https://github.com/hyodotdev/openiap-google/actions/workflows/ci.yml/badge.svg)](https://github.com/hyodotdev/openiap-google/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\nModern Android Kotlin library for in-app purchases using Google Play Billing Library v8.\n\n## 🌐 Learn More\n\nVisit [**openiap.dev**](https://openiap.dev) for complete documentation, guides, and the full OpenIAP specification.\n\n## 🎯 Overview\n\nOpenIAP GMS is a modern, type-safe Kotlin library that simplifies Google Play in-app billing integration. It provides a clean, coroutine-based API that handles all the complexity of Google Play Billing while offering robust error handling and real-time purchase tracking.\n\n## ✨ Features\n\n- 🔐 **Google Play Billing v8** - Latest billing library with enhanced security\n- ⚡ **Kotlin Coroutines** - Modern async/await API\n- 🎯 **Type Safe** - Full Kotlin type safety with sealed classes\n- 🔄 **Real-time Events** - Purchase update and error listeners\n- 🧵 **Thread Safe** - Concurrent operations with proper synchronization\n- 📱 **Easy Integration** - Simple singleton pattern with context management\n- 🛡️ **Robust Error Handling** - Comprehensive error types with detailed messages\n- 🚀 **Production Ready** - Used in production apps\n\n## 📋 Requirements\n\n- **Minimum SDK**: 21 (Android 5.0)\n- **Compile SDK**: 34+\n- **Google Play Billing**: v8.0.0\n- **Kotlin**: 1.9.20+\n\n## 📦 Installation\n\nAdd to your module's `build.gradle.kts`:\n\n```kotlin\ndependencies {\n    implementation(\"io.github.hyochan.openiap:openiap-google:1.2.13\")\n}\n```\n\nOr `build.gradle`:\n\n```groovy\ndependencies {\n    implementation 'io.github.hyochan.openiap:openiap-google:1.2.13'\n}\n```\n\n## 🚀 Quick Start\n\n### 1. Initialize in Application\n\n```kotlin\nclass MyApplication : Application() {\n    override fun onCreate() {\n        super.onCreate()\n        OpenIAP.initialize(this)\n    }\n}\n```\n\n### 2. Basic Usage\n\n```kotlin\nclass MainActivity : AppCompatActivity() {\n    private lateinit var openIAP: OpenIAP\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        openIAP = OpenIAP.getInstance()\n\n        // Set up listeners\n        openIAP.addPurchaseUpdateListener { purchase -\u003e\n            handlePurchaseUpdate(purchase)\n        }\n\n        openIAP.addPurchaseErrorListener { error -\u003e\n            handlePurchaseError(error)\n        }\n\n        // Initialize connection\n        lifecycleScope.launch {\n            try {\n                val connected = openIAP.initConnection()\n                if (connected) {\n                    loadProducts()\n                }\n            } catch (e: OpenIapError) {\n                // Handle connection error\n            }\n        }\n    }\n\n    private suspend fun loadProducts() {\n        try {\n            val products = openIAP.fetchProducts(listOf(\"premium_upgrade\", \"remove_ads\"))\n            // Display products in UI\n        } catch (e: OpenIapError) {\n            // Handle error\n        }\n    }\n\n    private suspend fun purchaseProduct(productId: String) {\n        try {\n            openIAP.requestPurchase(\n                activity = this,\n                sku = productId\n            )\n        } catch (e: OpenIapError) {\n            // Handle purchase error\n        }\n    }\n\n    private fun handlePurchaseUpdate(purchase: OpenIapPurchase) {\n        when (purchase.purchaseState) {\n            PurchaseState.Purchased -\u003e {\n                // Acknowledge or consume the purchase\n                lifecycleScope.launch {\n                    try {\n                        purchase.purchaseToken?.let { token -\u003e\n                            openIAP.acknowledgePurchase(token)\n                            // Or for consumables: openIAP.consumePurchase(token)\n                        }\n                    } catch (e: OpenIapError) {\n                        // Handle error\n                    }\n                }\n            }\n            PurchaseState.Pending -\u003e {\n                // Purchase is pending (e.g., awaiting payment)\n            }\n            // Handle other states...\n        }\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        openIAP.clearListeners()\n        openIAP.endConnection()\n    }\n}\n```\n\n## 📚 API Reference\n\n### Core Methods\n\n#### Connection Management\n\n```kotlin\nsuspend fun initConnection(): Boolean\nfun endConnection()\nfun isReady(): Boolean\n```\n\n#### Product Management\n\n```kotlin\nsuspend fun fetchProducts(skus: List\u003cString\u003e): List\u003cOpenIapProduct\u003e\nsuspend fun fetchProducts(type: String, skus: List\u003cString\u003e): List\u003cOpenIapProduct\u003e\nfun getCachedProduct(sku: String): ProductDetails?\nfun getAllCachedProducts(): Map\u003cString, ProductDetails\u003e\n```\n\n#### Purchase Operations\n\n```kotlin\nsuspend fun requestPurchase(\n    activity: Activity,\n    sku: String,\n    offerToken: String? = null,\n    obfuscatedAccountId: String? = null,\n    obfuscatedProfileId: String? = null\n)\n\nsuspend fun requestPurchase(params: Map\u003cString, Any?\u003e, activity: Activity)\nsuspend fun finishTransaction(purchase: OpenIapPurchase, isConsumable: Boolean? = null)\nsuspend fun getAvailablePurchases(): List\u003cOpenIapPurchase\u003e\nsuspend fun getAvailablePurchases(options: Map\u003cString, Any?\u003e?): List\u003cOpenIapPurchase\u003e // options ignored on Android\nsuspend fun getAvailableItemsByType(type: String): List\u003cOpenIapPurchase\u003e\nsuspend fun acknowledgePurchase(purchaseToken: String): Boolean\nsuspend fun consumePurchase(purchaseToken: String): Boolean\n```\n\n\u003e Note: Use `\"in-app\"` for in-app product types. The legacy alias `\"inapp\"` remains available for compatibility but will be removed in version 1.2.0.\n\n#### Store Information\n\n```kotlin\nsuspend fun getStorefront(): String\n```\n\n### Subscription Management\n\n```kotlin\nsuspend fun getActiveSubscriptions(subscriptionIds: List\u003cString\u003e? = null): List\u003cOpenIapActiveSubscription\u003e\nsuspend fun hasActiveSubscriptions(subscriptionIds: List\u003cString\u003e? = null): Boolean\nfun deepLinkToSubscriptions(): Boolean\n```\n\n### Event Listeners\n\n```kotlin\nfun addPurchaseUpdateListener(listener: OpenIapPurchaseUpdateListener)\nfun removePurchaseUpdateListener(listener: OpenIapPurchaseUpdateListener)\nfun addPurchaseErrorListener(listener: OpenIapPurchaseErrorListener)\nfun removePurchaseErrorListener(listener: OpenIapPurchaseErrorListener)\n\n// Convenience methods\nfun addListener(listener: OpenIapListener)\nfun removeListener(listener: OpenIapListener)\nfun clearListeners()\n```\n\n### Data Models\n\n#### OpenIapProduct\n\n```kotlin\ndata class OpenIapProduct(\n    val id: String,\n    val title: String,\n    val description: String,\n    val price: Double?,\n    val displayPrice: String,\n    val currency: String,\n    val type: ProductType,\n    val platform: String = \"android\",\n    val displayName: String?,\n    val debugDescription: String?,\n    val nameAndroid: String?,\n    val oneTimePurchaseOfferDetails: OneTimePurchaseOfferDetails?,\n    val subscriptionOfferDetails: List\u003cSubscriptionOfferDetails\u003e?\n)\n```\n\n#### OpenIapPurchase\n\n```kotlin\ndata class OpenIapPurchase(\n    val id: String,                  // transactionId\n    val productId: String,\n    val ids: List\u003cString\u003e?,          // alias of productIds\n    val transactionDate: Double,\n    val transactionReceipt: String,\n    val purchaseToken: String?,\n    val platform: String = \"android\",\n    val quantity: Int = 1,\n    val transactionId: String?,\n    val purchaseTime: Long,\n    val purchaseState: PurchaseState,\n    val isAutoRenewing: Boolean,\n    // ... Android-specific fields\n    val isAcknowledgedAndroid: Boolean?,\n    val autoRenewingAndroid: Boolean?,\n    // ... many more fields\n)\n```\n\n#### Error Handling\n\n```kotlin\nsealed class OpenIapError : Exception {\n    object UserCancelled : OpenIapError()\n    object ItemAlreadyOwned : OpenIapError()\n    object ItemNotOwned : OpenIapError()\n    data class ProductNotFound(val productId: String) : OpenIapError()\n    data class PurchaseFailed(override val message: String) : OpenIapError()\n    // ... many more error types\n}\n```\n\n## 🔄 Purchase Flow\n\n1. **Initialize**: Call `initConnection()`\n2. **Fetch Products**: Use `fetchProducts()` to load available items\n3. **Request Purchase**: Call `requestPurchase()` with the product SKU\n4. **Handle Events**: Listen for purchase updates via listeners\n5. **Process Purchase**: Acknowledge non-consumables or consume consumables\n6. **Server Verification**: Always verify purchases on your backend\n\n## 🛡️ Security Best Practices\n\n- **Server-Side Verification**: Always verify purchases on your backend server\n- **Acknowledge Promptly**: Acknowledge non-consumable purchases within 3 days\n- **Consume Consumables**: Consume consumable purchases after granting content\n- **Handle All States**: Implement proper handling for all purchase states\n- **Error Handling**: Implement comprehensive error handling\n\n## 🧪 Testing\n\nThe library includes a comprehensive sample app demonstrating all features:\n\n```bash\ngit clone https://github.com/hyodotdev/openiap-google.git\ncd openiap-google\n./gradlew :sample:installDebug\n```\n\n### Test Products\n\nFor development, use Google Play's test SKUs:\n\n- `android.test.purchased` - Always succeeds\n- `android.test.canceled` - Always cancels\n- `android.test.item_unavailable` - Always fails\n\nFor production testing, configure products in Google Play Console and use internal testing.\n\n## 📱 Sample App\n\nThe included sample app demonstrates:\n\n- ✅ Connection management with retry logic\n- ✅ Product listing and purchase flow\n- ✅ Real-time purchase event handling\n- ✅ Purchase history and management\n- ✅ Error handling and user feedback\n- ✅ Android-specific billing features\n\n## 🔧 Advanced Usage\n\n### Custom Error Handling\n\n```kotlin\ntry {\n    openIAP.requestPurchase(this, \"premium_upgrade\")\n} catch (e: OpenIapError) {\n    when (e) {\n        OpenIapError.UserCancelled -\u003e {\n            // User cancelled, no action needed\n        }\n        OpenIapError.ItemAlreadyOwned -\u003e {\n            // Item already purchased\n            showMessage(\"You already own this item!\")\n        }\n        is OpenIapError.ProductNotFound -\u003e {\n            // Product not available\n            showError(\"Product ${e.productId} not found\")\n        }\n        // Handle other error types...\n        else -\u003e {\n            showError(\"Purchase failed: ${e.message}\")\n        }\n    }\n}\n```\n\n### Subscription Offers\n\n```kotlin\n// Get subscription offers\nval product = openIAP.getCachedProduct(\"monthly_subscription\")\nval offers = product?.subscriptionOfferDetails\n\n// Purchase with specific offer\nval offerToken = offers?.firstOrNull()?.offerToken\nopenIAP.requestPurchase(\n    activity = this,\n    sku = \"monthly_subscription\",\n    offerToken = offerToken\n)\n```\n\n## ⚠️ Important Notes\n\n- This library requires Google Play Billing Library v8\n- Test with real Google Play Console products for production\n- Always verify purchases server-side for security\n- Handle all purchase states properly\n- Clean up listeners and connections in `onDestroy()`\n\n## 🔧 Troubleshooting\n\n### Common Issues\n\n1. **Product not found**\n\n   - Ensure products are configured in Google Play Console\n   - App must be uploaded to Google Play Console (even as draft)\n   - Wait up to 24 hours for products to become available\n\n2. **Billing unavailable**\n\n   - Verify Google Play Services are installed and updated\n   - Check that app is signed with release key for testing\n   - Ensure billing permissions are in AndroidManifest.xml\n\n3. **Purchase not triggering**\n   - Use real device with Google Play Store\n   - Avoid emulators without Google Play Services\n   - Check that test account has payment method\n\n### Debug Mode\n\nEnable verbose logging to see detailed billing operations:\n\n```kotlin\n// In development builds\nif (BuildConfig.DEBUG) {\n    Log.d(\"OpenIAP\", \"Debug mode enabled\")\n}\n```\n\n## 📄 License\n\n```txt\nMIT License\n\nCopyright (c) 2025 hyo.dev\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\n## 🤝 Contributing\n\nContributions are welcome! Please read our contributing guidelines and submit pull requests.\n\n## 📞 Support\n\n- **Issues**: [GitHub Issues](https://github.com/hyodotdev/openiap-google/issues)\n- **Discussions**: [OpenIAP Discussions](https://github.com/hyodotdev/openiap.dev/discussions)\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003cstrong\u003eBuilt with ❤️ for the OpenIAP community\u003c/strong\u003e\n  \n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyodotdev%2Fopeniap-google","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyodotdev%2Fopeniap-google","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyodotdev%2Fopeniap-google/lists"}