-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
84af5cf
commit e31e66c
Showing
6 changed files
with
368 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# These are supported funding model platforms | ||
|
||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] | ||
patreon: codewithmax | ||
open_collective: # Replace with a single Open Collective username | ||
ko_fi: codewithmax | ||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel | ||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry | ||
liberapay: # Replace with a single Liberapay username | ||
issuehunt: # Replace with a single IssueHunt username | ||
otechie: # Replace with a single Otechie username | ||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry | ||
custom: ['https://boosty.to/codewithmax'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
# AndroidIAPP is a plugin for the Godot game engine. | ||
# It provides an interface to work with Google Play Billing Library version 7. | ||
# The plugin supports all public functions of the library, passes all error codes, and can work with different subscription plans. | ||
# https://developer.android.com/google/play/billing | ||
# | ||
# You can use this plugin with any node in Godot. | ||
# But, I recommend adding this script as a singleton (autoload). | ||
# This makes it easier to access and use its functions from anywhere in your project. | ||
# | ||
# An example of working with a plugin: | ||
|
||
|
||
extends Node | ||
|
||
|
||
# https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState | ||
enum purchaseState { | ||
UNSPECIFIED_STATE = 0, | ||
PURCHASED = 1, | ||
PENDING = 2, | ||
} | ||
|
||
|
||
# https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode | ||
enum billingResponseCode { | ||
SERVICE_TIMEOUT = -3, | ||
FEATURE_NOT_SUPPORTED = -2, | ||
SERVICE_DISCONNECTED = -1, | ||
OK = 0, | ||
USER_CANCELED = 1, | ||
SERVICE_UNAVAILABLE = 2, | ||
BILLING_UNAVAILABLE = 3, | ||
ITEM_UNAVAILABLE = 4, | ||
DEVELOPER_ERROR = 5, | ||
ERROR = 6, | ||
ITEM_ALREADY_OWNED = 7, | ||
ITEM_NOT_OWNED = 8, | ||
NETWORK_ERROR = 12 | ||
} | ||
|
||
|
||
const ITEM_CONSUMATED: Array = [ | ||
"additional_life_v1", | ||
] | ||
|
||
const ITEM_ACKNOWLEDGED: Array = [ | ||
"red_skin_v1", | ||
"blue_skin_v1", | ||
"yellow_skin_v1", | ||
] | ||
|
||
const SUBSCRIPTIONS: Array = [ | ||
"remove_ads_sub_01", | ||
"test_iapp_v7", | ||
] | ||
|
||
|
||
var billing = null | ||
|
||
|
||
# Called when the node enters the scene tree for the first time. | ||
func _ready() -> void: | ||
await get_tree().create_timer(1).timeout | ||
run_iapp_billing() | ||
|
||
|
||
func run_iapp_billing(): | ||
if Engine.has_singleton("AndroidIAPP"): | ||
# Get the singleton instance of AndroidIAPP | ||
billing = Engine.get_singleton("AndroidIAPP") | ||
print("AndroidIAPP singleton loaded") | ||
|
||
# Connection information | ||
|
||
# Handle the response from the helloResponse signal | ||
billing.helloResponse.connect(_on_hello_response) | ||
# Handle the startConnection signal | ||
billing.startConnection.connect(_on_start_connection) | ||
# Handle the connected signal | ||
billing.connected.connect(_on_connected) | ||
# Handle the disconnected signal | ||
billing.disconnected.connect(_on_disconnected) | ||
|
||
# Querying purchases | ||
|
||
# Handle the response from the query_purchases signal | ||
billing.query_purchases.connect(_on_query_purchases) | ||
# Handle the query_purchases_error signal | ||
billing.query_purchases_error.connect(_on_query_purchases_error) | ||
|
||
# Querying products details | ||
|
||
# Handle the response from the query_product_details signal | ||
billing.query_product_details.connect(query_product_details) | ||
# Handle the query_product_details_error signal | ||
billing.query_product_details_error.connect(_on_query_product_details_error) | ||
|
||
# Purchase processing | ||
|
||
# Handle the purchase signal | ||
billing.purchase.connect(_on_purchase) | ||
# Handle the purchase_error signal | ||
billing.purchase_error.connect(_on_purchase_error) | ||
|
||
# Purchase updating | ||
|
||
# Handle the purchase_updated signal | ||
billing.purchase_updated.connect(_on_purchase_updated) | ||
# Handle the purchase_cancelled signal | ||
billing.purchase_cancelled.connect(_on_purchase_cancelled) | ||
# Handle the purchase_update_error signal | ||
billing.purchase_update_error.connect(_on_purchase_update_error) | ||
|
||
# Purchase consuming | ||
|
||
# Handle the purchase_consumed signal | ||
billing.purchase_consumed.connect(_on_purchase_consumed) | ||
# Handle the purchase_consumed_error signal | ||
billing.purchase_consumed_error.connect(_on_purchase_consumed_error) | ||
|
||
# Purchase acknowledging | ||
|
||
# Handle the purchase_acknowledged signal | ||
billing.purchase_acknowledged.connect(_on_purchase_acknowledged) | ||
# Handle the purchase_acknowledged_error signal | ||
billing.purchase_acknowledged_error.connect(_on_purchase_acknowledged_error) | ||
|
||
# Connection | ||
billing.startConnection() | ||
else: | ||
printerr("AndroidIAPP singleton not found") | ||
|
||
|
||
func _on_start_connection() -> void: | ||
print("Billing: start connection") | ||
|
||
|
||
func _on_connected() -> void: | ||
print("Billing successfully connected") | ||
await get_tree().create_timer(0.4).timeout | ||
if billing.isReady(): | ||
# billing.sayHello("Hello from Godot Google IAPP plugin :)") | ||
# Show products available to buy | ||
# https://developer.android.com/google/play/billing/integrate#show-products | ||
billing.queryProductDetails(ITEM_ACKNOWLEDGED, "inapp") | ||
billing.queryProductDetails(ITEM_CONSUMATED, "inapp") | ||
billing.queryProductDetails(SUBSCRIPTIONS, "subs") | ||
# Handling purchases made outside your app | ||
# https://developer.android.com/google/play/billing/integrate#ooap | ||
billing.queryPurchases("subs") | ||
billing.queryPurchases("inapp") | ||
|
||
|
||
func _on_disconnected() -> void: | ||
print("Billing disconnected") | ||
|
||
|
||
func _on_hello_response(response) -> void: | ||
print("Hello signal response: " + response) | ||
|
||
|
||
func query_product_details(response) -> void: | ||
for i in response["product_details_list"].size(): | ||
var product = response["product_details_list"][i] | ||
print(JSON.stringify(product["product_id"], " ")) | ||
# | ||
# Handle avaible for purchase product details here | ||
# | ||
|
||
|
||
func _on_query_purchases(response) -> void: | ||
print("on_query_Purchases_response: ") | ||
for purchase in response["purchases_list"]: | ||
process_purchase(purchase) | ||
|
||
|
||
func _on_purchase_updated(response): | ||
for purchase in response["purchases_list"]: | ||
process_purchase(purchase) | ||
|
||
|
||
# Processing incoming purchase | ||
func process_purchase(purchase): | ||
for product in purchase["products"]: | ||
if (product in ITEM_ACKNOWLEDGED) or (product in SUBSCRIPTIONS): | ||
# Acknowledge the purchase | ||
if not purchase["is_acknowledged"]: | ||
print("Acknowledging: " + purchase["purchase_token"]) | ||
billing.acknowledgePurchase(purchase["purchase_token"]) | ||
# | ||
# Here, process the use of the product in your game. | ||
# | ||
else: | ||
print("Already acknowledged") | ||
elif product in ITEM_CONSUMATED: | ||
# Consume the purchase | ||
print("Consuming: " + purchase["purchase_token"]) | ||
billing.consumePurchase(purchase["purchase_token"]) | ||
# | ||
# Here, process the use of the product in your game. | ||
# | ||
else: | ||
print("Product not found: " + str(product)) | ||
|
||
|
||
# Purchase | ||
func do_purchase(id: String, is_personalized: bool = false): | ||
billing.purchase([id], is_personalized) | ||
|
||
# Subscriptions | ||
func do_subsciption(subscription_id: String, base_plan_id: String , is_personalized: bool = false): | ||
billing.subscribe([subscription_id], [base_plan_id], is_personalized) | ||
|
||
|
||
func print_purchases(purchases): | ||
for purchase in purchases: | ||
print(JSON.stringify(purchase, " ")) | ||
|
||
|
||
func _on_purchase(response) -> void: | ||
print("Purchase started:") | ||
print(JSON.stringify(response, " ")) | ||
|
||
|
||
func _on_purchase_cancelled(response) -> void: | ||
print("Purchase_cancelled:") | ||
print(JSON.stringify(response, " ")) | ||
|
||
|
||
func _on_purchase_consumed(response) -> void: | ||
print("Purchase_consumed:") | ||
print(JSON.stringify(response, " ")) | ||
|
||
|
||
func _on_purchase_acknowledged(response) -> void: | ||
print("Purchase_acknowledged:") | ||
print(JSON.stringify(response, " ")) | ||
|
||
|
||
func _on_purchase_update_error(error) -> void: | ||
print(JSON.stringify(error, " ")) | ||
|
||
|
||
func _on_purchase_error(error) -> void: | ||
print(JSON.stringify(error, " ")) | ||
|
||
|
||
func _on_purchase_consumed_error(error) -> void: | ||
print(JSON.stringify(error, " ")) | ||
|
||
|
||
func _on_purchase_acknowledged_error(error) -> void: | ||
print(JSON.stringify(error, " ")) | ||
|
||
|
||
func _on_query_purchases_error(error) -> void: | ||
print(JSON.stringify(error, " ")) | ||
|
||
|
||
func _on_query_product_details_error(error) -> void: | ||
print(JSON.stringify(error, " ")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"description": "Beautiful sky-blue skin for circle catcher.", | ||
"hash_code": 1042382311, | ||
"name": "Blue skin", | ||
"one_time_purchase_offer_details": { | ||
"formatted_price": "1,29 CA$", | ||
"price_amount_micros": 1290000, | ||
"price_currency_code": "CAD" | ||
}, | ||
"product_id": "blue_skin_v1", | ||
"product_type": "inapp", | ||
"title": "Blue skin (Circle catcher 2)", | ||
"to_string": "ProductDetails{jsonString='{\"productId\":\"blue_skin_v1\",\"type\":\"inapp\",\"title\":\"Blue skin (Circle catcher 2)\",\"name\":\"Blue skin\",\"description\":\"Beautiful sky-blue skin for circle catcher.\",\"localizedIn\":[\"en-US\"],\"skuDetailsToken\":\"AEuhp4Ik3jZtacec7suJ2k1UwRNw1TAURMDxhuBdJVAvUszGtiXhi5IouYzz023Wz_3n9L-VCkaEOvo=\",\"oneTimePurchaseOfferDetails\":{\"priceAmountMicros\":1290000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"1,29 CA$\",\"offerIdToken\":\"AbNbjn6qd8NV87Re\\/Gu8BaDG15I1ttYTPGQklCYCEKswhA2AYrbJgEaLxvr8PzAhsQYGGMuXkxbh\\/8kb2wySL7bDGg==\"}}', parsedJson={\"productId\":\"blue_skin_v1\",\"type\":\"inapp\",\"title\":\"Blue skin (Circle catcher 2)\",\"name\":\"Blue skin\",\"description\":\"Beautiful sky-blue skin for circle catcher.\",\"localizedIn\":[\"en-US\"],\"skuDetailsToken\":\"AEuhp4Ik3jZtacec7suJ2k1UwRNw1TAURMDxhuBdJVAvUszGtiXhi5IouYzz023Wz_3n9L-VCkaEOvo=\",\"oneTimePurchaseOfferDetails\":{\"priceAmountMicros\":1290000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"1,29 CA$\",\"offerIdToken\":\"AbNbjn6qd8NV87Re\\/Gu8BaDG15I1ttYTPGQklCYCEKswhA2AYrbJgEaLxvr8PzAhsQYGGMuXkxbh\\/8kb2wySL7bDGg==\"}}, productId='blue_skin_v1', productType='inapp', title='Blue skin (Circle catcher 2)', productDetailsToken='AEuhp4Ik3jZtacec7suJ2k1UwRNw1TAURMDxhuBdJVAvUszGtiXhi5IouYzz023Wz_3n9L-VCkaEOvo=', subscriptionOfferDetails=null}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
{ | ||
"description": "Remove all ADs from app one one year.", | ||
"hash_code": -1341575204, | ||
"name": "Remove all ADs from app", | ||
"product_id": "remove_ads_sub_01", | ||
"product_type": "subs", | ||
"subscription_offer_details": [ | ||
{ | ||
"base_plan_id": "remove-ads-on-mounth", | ||
"installment_plan_details": { | ||
|
||
}, | ||
"offer_id": null, | ||
"offer_tags": [ | ||
"ads", | ||
"mounth" | ||
], | ||
"offer_token": "AbNbjn6TaIQy+qPjOjdLgFDKeSMVXjCx1DDgdhYNjVblNZ0d2GRCLJ/FWAFnIsPUe8NER3mp64JbMnUXORLfCMKLmc046GWIIdZy9jc=", | ||
"pricing_phases": [ | ||
{ | ||
"billing_cycle_count": 0, | ||
"billing_period": "P1M", | ||
"formatted_price": "1,39 CA$", | ||
"price_amount_micros": 1390000, | ||
"price_currency_code": "CAD", | ||
"recurrence_mode": 1 | ||
} | ||
] | ||
}, | ||
{ | ||
"base_plan_id": "remove-ads-on-year", | ||
"installment_plan_details": { | ||
|
||
}, | ||
"offer_id": null, | ||
"offer_tags": [ | ||
"ads", | ||
"year" | ||
], | ||
"offer_token": "AbNbjn4L6u7g6/hdXadrh8DN5gpEJ6Df9qwu9zvrwSSNpDZ/xwktiJ1668rLTaBQcC/cZsh6964WTWIjXPgIeoy7BACAMtaSi5nL", | ||
"pricing_phases": [ | ||
{ | ||
"billing_cycle_count": 0, | ||
"billing_period": "P1Y", | ||
"formatted_price": "12,99 CA$", | ||
"price_amount_micros": 12990000, | ||
"price_currency_code": "CAD", | ||
"recurrence_mode": 1 | ||
} | ||
] | ||
} | ||
], | ||
"title": "Remove all ADs from app (Circle catcher 2)", | ||
"to_string": "ProductDetails{jsonString='{\"productId\":\"remove_ads_sub_01\",\"type\":\"subs\",\"title\":\"Remove all ADs from app (Circle catcher 2)\",\"name\":\"Remove all ADs from app\",\"description\":\"Remove all ADs from app one one year.\",\"localizedIn\":[\"en-US\"],\"skuDetailsToken\":\"AEuhp4ILup4nhJvTjaewXqded-BbLooEPhm9MvUQWBuQ27NI1U6D1cN7E6Yi_E8pMzqc\",\"subscriptionOfferDetails\":[{\"offerIdToken\":\"AbNbjn6TaIQy+qPjOjdLgFDKeSMVXjCx1DDgdhYNjVblNZ0d2GRCLJ\\/FWAFnIsPUe8NER3mp64JbMnUXORLfCMKLmc046GWIIdZy9jc=\",\"basePlanId\":\"remove-ads-on-mounth\",\"pricingPhases\":[{\"priceAmountMicros\":1390000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"1,39 CA$\",\"billingPeriod\":\"P1M\",\"recurrenceMode\":1}],\"offerTags\":[\"ads\",\"mounth\"]},{\"offerIdToken\":\"AbNbjn4L6u7g6\\/hdXadrh8DN5gpEJ6Df9qwu9zvrwSSNpDZ\\/xwktiJ1668rLTaBQcC\\/cZsh6964WTWIjXPgIeoy7BACAMtaSi5nL\",\"basePlanId\":\"remove-ads-on-year\",\"pricingPhases\":[{\"priceAmountMicros\":12990000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"12,99 CA$\",\"billingPeriod\":\"P1Y\",\"recurrenceMode\":1}],\"offerTags\":[\"ads\",\"year\"]}]}', parsedJson={\"productId\":\"remove_ads_sub_01\",\"type\":\"subs\",\"title\":\"Remove all ADs from app (Circle catcher 2)\",\"name\":\"Remove all ADs from app\",\"description\":\"Remove all ADs from app one one year.\",\"localizedIn\":[\"en-US\"],\"skuDetailsToken\":\"AEuhp4ILup4nhJvTjaewXqded-BbLooEPhm9MvUQWBuQ27NI1U6D1cN7E6Yi_E8pMzqc\",\"subscriptionOfferDetails\":[{\"offerIdToken\":\"AbNbjn6TaIQy+qPjOjdLgFDKeSMVXjCx1DDgdhYNjVblNZ0d2GRCLJ\\/FWAFnIsPUe8NER3mp64JbMnUXORLfCMKLmc046GWIIdZy9jc=\",\"basePlanId\":\"remove-ads-on-mounth\",\"pricingPhases\":[{\"priceAmountMicros\":1390000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"1,39 CA$\",\"billingPeriod\":\"P1M\",\"recurrenceMode\":1}],\"offerTags\":[\"ads\",\"mounth\"]},{\"offerIdToken\":\"AbNbjn4L6u7g6\\/hdXadrh8DN5gpEJ6Df9qwu9zvrwSSNpDZ\\/xwktiJ1668rLTaBQcC\\/cZsh6964WTWIjXPgIeoy7BACAMtaSi5nL\",\"basePlanId\":\"remove-ads-on-year\",\"pricingPhases\":[{\"priceAmountMicros\":12990000,\"priceCurrencyCode\":\"CAD\",\"formattedPrice\":\"12,99 CA$\",\"billingPeriod\":\"P1Y\",\"recurrenceMode\":1}],\"offerTags\":[\"ads\",\"year\"]}]}, productId='remove_ads_sub_01', productType='subs', title='Remove all ADs from app (Circle catcher 2)', productDetailsToken='AEuhp4ILup4nhJvTjaewXqded-BbLooEPhm9MvUQWBuQ27NI1U6D1cN7E6Yi_E8pMzqc', subscriptionOfferDetails=[com.android.billingclient.api.ProductDetails$SubscriptionOfferDetails@e3d71fe, com.android.billingclient.api.ProductDetails$SubscriptionOfferDetails@1591d5f]}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"account_identifiers": null, | ||
"developer_payload": "", | ||
"hash_code": 347836291, | ||
"is_acknowledged": false, | ||
"is_auto_renewing": false, | ||
"order_id": "GPA.3386-6160-2931-85348", | ||
"original_json": "{\"orderId\":\"GPA.3386-6160-2931-85348\",\"packageName\":\"org.godotengine.circlecatcher\",\"productId\":\"blue_skin_v1\",\"purchaseTime\":1718385548694,\"purchaseState\":0,\"purchaseToken\":\"hbecfldgjckddhaefmoomgdm.AO-J1OxmTkHVIaH0xGRLKk53AvFGuj2gwKmldZ6YLAdfKTigvqE306j3cW38a_H8zd-DTr5-ZB-rWSbqUZFRuDpT3rGQyiicFN4e8VNd6qv4NWjc7L1opSU\",\"quantity\":1,\"acknowledged\":false}", | ||
"package_name": "org.godotengine.circlecatcher", | ||
"pending_purchase_update": null, | ||
"products": [ | ||
"blue_skin_v1" | ||
], | ||
"purchase_state": 1, | ||
"purchase_time": 1718385548694, | ||
"purchase_token": "hbecfldgjckddhaefmoomgdm.AO-J1OxmTkHVIaH0xGRLKk53AvFGuj2gwKmldZ6YLAdfKTigvqE306j3cW38a_H8zd-DTr5-ZB-rWSbqUZFRuDpT3rGQyiicFN4e8VNd6qv4NWjc7L1opSU", | ||
"quantity": 1, | ||
"signature": "A0NkdhKPTSubDkUgu9HzVvJ33G0bZ18a/LX5NoK5WHXZmO3qznf8GESw/bda1A76CbX0PpiDaDIWGLK8b0huTmmdxSL+2wjw+LnaABc+hSf6KjD8Zmu/doMA6ScihP9Ilv9/t18S8JFpJdvUOUvKMs//EP0bxvmxJbAin+Y8QUdKuL7Bgj4NY75Vka4UWbqApyGdRYOkU5R4DZXV8zhaeRbbbevOmWd4AgLctJv+ZhVSeWyY9g5ONlPutVPPg3nwz4RBFL49yIarXGKvaZicM1weqJX5rtV/H/2fTSTUqp/vqigZEDYGI/MzLQw8M6GjI2qUSuFf8MMu+Pvl5zPW4A==", | ||
"to_string": "Purchase. Json: {\"orderId\":\"GPA.3386-6160-2931-85348\",\"packageName\":\"org.godotengine.circlecatcher\",\"productId\":\"blue_skin_v1\",\"purchaseTime\":1718385548694,\"purchaseState\":0,\"purchaseToken\":\"hbecfldgjckddhaefmoomgdm.AO-J1OxmTkHVIaH0xGRLKk53AvFGuj2gwKmldZ6YLAdfKTigvqE306j3cW38a_H8zd-DTr5-ZB-rWSbqUZFRuDpT3rGQyiicFN4e8VNd6qv4NWjc7L1opSU\",\"quantity\":1,\"acknowledged\":false}" | ||
} |