mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-04 06:09:46 +03:00
Merge pull request #507 from ricardoalcantara/mono_android_iap
Rewriting Mono Android IAP to match with GDScript
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android IAP with C#", "Android IAP with C#.csproj", "{FA89D4C3-B45B-49F1-A975-BF059CA82D86}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
|
||||
{FA89D4C3-B45B-49F1-A975-BF059CA82D86}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -3,11 +3,11 @@
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{FA89D4C3-B45B-49F1-A975-BF059CA82D86}</ProjectGuid>
|
||||
<ProjectGuid>{480953C3-B1FD-42F6-8A07-51A3F69024D7}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<OutputPath>.mono\temp\bin\$(Configuration)</OutputPath>
|
||||
<RootNamespace>AndroidIAPwithC</RootNamespace>
|
||||
<AssemblyName>Android IAP with C#</AssemblyName>
|
||||
<RootNamespace>AndroidInAppPurchasesWithCSharp</RootNamespace>
|
||||
<AssemblyName>Android in-app purchases with C#</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||
<GodotProjectGeneratorVersion>1.0.0.0</GodotProjectGeneratorVersion>
|
||||
<BaseIntermediateOutputPath>.mono\temp\obj</BaseIntermediateOutputPath>
|
||||
@@ -47,12 +47,12 @@
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<Reference Include="GodotSharp">
|
||||
<HintPath>$(ProjectDir)\.mono\assemblies\$(ApiConfiguration)\GodotSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="GodotSharpEditor" Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<HintPath>$(ProjectDir)\.mono\assemblies\$(ApiConfiguration)\GodotSharpEditor.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharpEditor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
19
mono/android_iap/Android in-app purchases with C#.sln
Normal file
19
mono/android_iap/Android in-app purchases with C#.sln
Normal file
@@ -0,0 +1,19 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2012
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android in-app purchases with C#", "Android in-app purchases with C#.csproj", "{480953C3-B1FD-42F6-8A07-51A3F69024D7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
|
||||
{480953C3-B1FD-42F6-8A07-51A3F69024D7}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,7 +1,7 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
// https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode
|
||||
public enum BillingResponseCode
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Godot.Collections;
|
||||
using Godot;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
public enum PurchaseType
|
||||
{
|
||||
@@ -21,18 +21,20 @@ namespace Android_Iap.GodotGooglePlayBilling
|
||||
[Signal] public delegate void PurchaseAcknowledged(string purchaseToken);
|
||||
[Signal] public delegate void PurchaseAcknowledgementError(int code, string message);
|
||||
[Signal] public delegate void PurchaseConsumed(string purchaseToken);
|
||||
[Signal] public delegate void PurchaseConsumption_error(int code, string message, string purchaseToken);
|
||||
[Signal] public delegate void PurchaseConsumptionError(int code, string message, string purchaseToken);
|
||||
|
||||
[Export] public bool AutoReconnect { get; set; }
|
||||
[Export] public bool AutoConnect { get; set; }
|
||||
|
||||
public bool IsAvailable { get; private set; }
|
||||
|
||||
private Object _payment;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
if (Engine.HasSingleton("GodotGooglePlayBilling"))
|
||||
{
|
||||
GD.Print("GodotGooglePlayBilling HasSingleton");
|
||||
IsAvailable = true;
|
||||
_payment = Engine.GetSingleton("GodotGooglePlayBilling");
|
||||
// These are all signals supported by the API
|
||||
// You can drop some of these based on your needs
|
||||
@@ -47,12 +49,10 @@ namespace Android_Iap.GodotGooglePlayBilling
|
||||
_payment.Connect("purchase_acknowledgement_error", this, nameof(OnGodotGooglePlayBilling_purchase_acknowledgement_error)); // Response ID (int), Debug message (string), Purchase token (string)
|
||||
_payment.Connect("purchase_consumed", this, nameof(OnGodotGooglePlayBilling_purchase_consumed)); // Purchase token (string)
|
||||
_payment.Connect("purchase_consumption_error", this, nameof(OnGodotGooglePlayBilling_purchase_consumption_error)); // Response ID (int), Debug message (string), Purchase token (string)
|
||||
|
||||
if (AutoConnect) StartConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print("GPB: Android IAP support is not enabled. Make sure you have enabled 'Custom Build' and the GodotGooglePlayBilling plugin in your Android export settings! IAP will not work.");
|
||||
IsAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,14 @@ namespace Android_Iap.GodotGooglePlayBilling
|
||||
|
||||
public void EndConnection() => _payment?.Call("endConnection");
|
||||
|
||||
public void QuerySkuDetails(string[] querySkuDetails, PurchaseType type) => _payment?.Call("querySkuDetails", querySkuDetails, $"{type}".ToLower());
|
||||
|
||||
public bool IsReady() => (_payment?.Call("isReady") as bool?) ?? false;
|
||||
|
||||
public void AcknowledgePurchase(string purchaseToken) => _payment?.Call("acknowledgePurchase", purchaseToken);
|
||||
|
||||
public void ConsumePurchase(string purchaseToken) => _payment?.Call("consumePurchase", purchaseToken);
|
||||
|
||||
public BillingResult Purchase(string sku)
|
||||
{
|
||||
if (_payment == null) return null;
|
||||
@@ -69,10 +77,6 @@ namespace Android_Iap.GodotGooglePlayBilling
|
||||
return new BillingResult(result);
|
||||
}
|
||||
|
||||
public void QuerySkuDetails(string[] querySkuDetails, PurchaseType type) => _payment?.Call("querySkuDetails", querySkuDetails, $"{type}".ToLower());
|
||||
|
||||
public bool IsReady() => (_payment?.Call("isReady") as bool?) ?? false;
|
||||
|
||||
public PurchasesResult QueryPurchases(PurchaseType purchaseType)
|
||||
{
|
||||
if (_payment == null) return null;
|
||||
@@ -80,85 +84,31 @@ namespace Android_Iap.GodotGooglePlayBilling
|
||||
return new PurchasesResult(result);
|
||||
}
|
||||
|
||||
public void AcknowledgePurchase(string purchaseToken) => _payment?.Call("acknowledgePurchase", purchaseToken);
|
||||
|
||||
public void ConsumePurchase(string purchaseToken) => _payment?.Call("consumePurchase", purchaseToken);
|
||||
|
||||
#endregion
|
||||
|
||||
#region GodotGooglePlayBilling Signals
|
||||
|
||||
private void OnGodotGooglePlayBilling_connected()
|
||||
{
|
||||
GD.Print("GodotGooglePlayBilling Connected");
|
||||
EmitSignal(nameof(Connected));
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_connected() => EmitSignal(nameof(Connected));
|
||||
|
||||
private async void OnGodotGooglePlayBilling_disconnected()
|
||||
{
|
||||
GD.Print("GodotGooglePlayBilling Disconnected");
|
||||
EmitSignal(nameof(Disconnected));
|
||||
private void OnGodotGooglePlayBilling_disconnected() => EmitSignal(nameof(Disconnected));
|
||||
|
||||
if (AutoReconnect)
|
||||
{
|
||||
await ToSignal(GetTree().CreateTimer(10), "timeout");
|
||||
StartConnection();
|
||||
}
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_connect_error(int code, string message) => EmitSignal(nameof(ConnectError), code, message);
|
||||
|
||||
private void OnGodotGooglePlayBilling_connect_error(int code, string message)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling ConnectError {code}: {message}");
|
||||
EmitSignal(nameof(ConnectError), code, message);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_sku_details_query_completed(Array skuDetails) => EmitSignal(nameof(SkuDetailsQueryCompleted), skuDetails);
|
||||
|
||||
private void OnGodotGooglePlayBilling_sku_details_query_completed(Array skuDetails)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling SkuDetailsQueryCompleted {skuDetails}");
|
||||
EmitSignal(nameof(SkuDetailsQueryCompleted), skuDetails);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_sku_details_query_error(int code, string message) => EmitSignal(nameof(SkuDetailsQueryError), code, message);
|
||||
|
||||
private void OnGodotGooglePlayBilling_sku_details_query_error(int code, string message)
|
||||
{
|
||||
GD.Print($"SkuDetailsQueryError error {code}: {message}");
|
||||
EmitSignal(nameof(SkuDetailsQueryError), code, message);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchases_updated(Array purchases) => EmitSignal(nameof(PurchasesUpdated), purchases);
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchases_updated(Array purchases)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchasesUpdated {purchases}");
|
||||
EmitSignal(nameof(PurchasesUpdated), purchases);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchase_error(int code, string message) => EmitSignal(nameof(PurchaseError), code, message);
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchase_error(int code, string message)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchaseError {code}: {message}");
|
||||
EmitSignal(nameof(PurchaseError), code, message);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchase_acknowledged(string purchaseToken) => EmitSignal(nameof(PurchaseAcknowledged), purchaseToken);
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchase_acknowledged(string purchaseToken)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchaseAcknowledged {purchaseToken}");
|
||||
EmitSignal(nameof(PurchaseAcknowledged), purchaseToken);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchase_acknowledgement_error(int code, string message) => EmitSignal(nameof(PurchaseAcknowledgementError), code, message);
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchase_acknowledgement_error(int code, string message)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchaseAcknowledgementError error {code}: {message}");
|
||||
EmitSignal(nameof(PurchaseAcknowledgementError), code, message);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchase_consumed(string purchaseToken) => EmitSignal(nameof(PurchaseConsumed), purchaseToken);
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchase_consumed(string purchaseToken)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchaseConsumed successfully: {purchaseToken}");
|
||||
EmitSignal(nameof(PurchaseConsumed), purchaseToken);
|
||||
}
|
||||
|
||||
private void OnGodotGooglePlayBilling_purchase_consumption_error(int code, string message, string purchaseToken)
|
||||
{
|
||||
GD.Print($"GodotGooglePlayBilling PurchaseConsumption_error error {code}: {message}, purchase token: {purchaseToken}");
|
||||
EmitSignal(nameof(PurchaseConsumption_error), code, message, purchaseToken);
|
||||
}
|
||||
private void OnGodotGooglePlayBilling_purchase_consumption_error(int code, string message, string purchaseToken) => EmitSignal(nameof(PurchaseConsumptionError), code, message, purchaseToken);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
public static class GooglePlayBillingUtils
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
// https://developer.android.com/reference/com/android/billingclient/api/Purchase.PurchaseState
|
||||
public enum PurchaseState
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
public class PurchasesResult : BillingResult
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Android_Iap.GodotGooglePlayBilling
|
||||
namespace AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling
|
||||
{
|
||||
public class SkuDetails
|
||||
{
|
||||
|
||||
@@ -1,170 +1,82 @@
|
||||
using Android_Iap.GodotGooglePlayBilling;
|
||||
using AndroidInAppPurchasesWithCSharp.GodotGooglePlayBilling;
|
||||
using Godot;
|
||||
using CoreGeneric = System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Android_Iap
|
||||
namespace AndroidInAppPurchasesWithCSharp
|
||||
{
|
||||
/*
|
||||
test skus
|
||||
android.test.purchased
|
||||
android.test.canceled
|
||||
android.test.refunded
|
||||
android.test.item_unavailable
|
||||
*/
|
||||
public class Main : Node2D
|
||||
public class Main : Control
|
||||
{
|
||||
private readonly string[] ArrInAppProductsSKUs = new string[]
|
||||
{
|
||||
"android.test.purchased",
|
||||
"android.test.canceled",
|
||||
"android.test.refunded",
|
||||
"android.test.item_unavailable"
|
||||
};
|
||||
const string TestItemSku = "my_in_app_purchase_sku";
|
||||
|
||||
private AcceptDialog _alertDialog;
|
||||
private Label _label;
|
||||
|
||||
private Button _buyPotionButton;
|
||||
private Label _totalPotionsLabel;
|
||||
private GooglePlayBilling _payment;
|
||||
|
||||
private Panel _panel;
|
||||
private Label _processLabel;
|
||||
private Label _thanksLabel;
|
||||
|
||||
private ProgressBar _playerLife;
|
||||
private StyleBoxFlat _playerLifeStyleBoxFlat;
|
||||
|
||||
private GooglePlayBilling _googlePlayBilling;
|
||||
private int _totalPotion = 5;
|
||||
|
||||
CoreGeneric.Dictionary<string, string> _purchases = new CoreGeneric.Dictionary<string, string>();
|
||||
private string _testItemPurchaseToken;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_googlePlayBilling = GetNode<GooglePlayBilling>("GooglePlayBilling");
|
||||
_payment = GetNode<GooglePlayBilling>("GooglePlayBilling");
|
||||
_alertDialog = GetNode<AcceptDialog>("AlertDialog");
|
||||
_label = GetNode<Label>("Label");
|
||||
|
||||
_buyPotionButton = GetNode<Button>("VBoxContainer2/BuyPotionButton");
|
||||
_totalPotionsLabel = GetNode<Label>("VBoxContainer/Label");
|
||||
|
||||
_panel = GetNode<Panel>("Panel");
|
||||
_processLabel = GetNode<Label>("Panel/ProcessLabel");
|
||||
_thanksLabel = GetNode<Label>("Panel/ThanksLabel");
|
||||
|
||||
_playerLife = GetNode<ProgressBar>("Sprite/ProgressBar");
|
||||
|
||||
_playerLifeStyleBoxFlat = _playerLife.Get("custom_styles/fg") as StyleBoxFlat;
|
||||
_playerLifeStyleBoxFlat.BgColor = Colors.Red.LinearInterpolate(Colors.Green, 1);
|
||||
|
||||
_playerLife.Value = 1;
|
||||
|
||||
_panel.Hide();
|
||||
_processLabel.Hide();
|
||||
_thanksLabel.Hide();
|
||||
_buyPotionButton.Hide();
|
||||
_totalPotionsLabel.Text = $"{_totalPotion} Potions";
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
{
|
||||
if (_playerLife.Value > 0.5)
|
||||
if (_payment.IsAvailable)
|
||||
{
|
||||
_playerLife.Value -= delta;
|
||||
}
|
||||
else if (_playerLife.Value > 0.2)
|
||||
{
|
||||
_playerLife.Value -= delta / 2;
|
||||
}
|
||||
else if (_playerLife.Value > 0.1)
|
||||
{
|
||||
_playerLife.Value -= delta / 4;
|
||||
}
|
||||
_label.Text += $"\n\n\nTest item SKU: {TestItemSku}";
|
||||
|
||||
_playerLifeStyleBoxFlat.BgColor = Colors.Red.LinearInterpolate(Colors.Green, Convert.ToSingle(_playerLife.Value));
|
||||
}
|
||||
|
||||
private void OnUsePotionButton_pressed()
|
||||
{
|
||||
if (_totalPotion > 0)
|
||||
{
|
||||
_totalPotion -= 1;
|
||||
_totalPotionsLabel.Text = $"{_totalPotion} Potions";
|
||||
_playerLifeStyleBoxFlat.BgColor = Colors.Red.LinearInterpolate(Colors.Green, Convert.ToSingle(_playerLife.Value));
|
||||
|
||||
_playerLife.Value += 20;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBuyPotionButton_pressed()
|
||||
{
|
||||
var result = _googlePlayBilling.Purchase("android.test.purchased");
|
||||
if (result != null && result.Status == (int)Error.Ok)
|
||||
{
|
||||
GD.Print("Purchase Requested");
|
||||
// No params.
|
||||
_payment.Connect(nameof(GooglePlayBilling.Connected), this, nameof(OnConnected));
|
||||
// No params.
|
||||
_payment.Connect(nameof(GooglePlayBilling.Disconnected), this, nameof(OnDisconnected));
|
||||
// Response ID (int), Debug message (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.ConnectError), this, nameof(OnConnectError));
|
||||
// Purchases (Dictionary[]).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchasesUpdated), this, nameof(OnPurchasesUpdated));
|
||||
// Response ID (int), Debug message (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchaseError), this, nameof(OnPurchaseError));
|
||||
// SKUs (Dictionary[]).
|
||||
_payment.Connect(nameof(GooglePlayBilling.SkuDetailsQueryCompleted), this, nameof(OnSkuDetailsQueryCompleted));
|
||||
// Response ID (int), Debug message (string), Queried SKUs (string[]).
|
||||
_payment.Connect(nameof(GooglePlayBilling.SkuDetailsQueryError), this, nameof(OnSkuDetailsQueryError));
|
||||
// Purchase token (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchaseAcknowledged), this, nameof(OnPurchaseAcknowledged));
|
||||
// Response ID (int), Debug message (string), Purchase token (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchaseAcknowledgementError), this, nameof(OnPurchaseAcknowledgementError));
|
||||
// Purchase token (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchaseConsumed), this, nameof(OnPurchaseConsumed));
|
||||
// Response ID (int), Debug message (string), Purchase token (string).
|
||||
_payment.Connect(nameof(GooglePlayBilling.PurchaseConsumptionError), this, nameof(OnPurchaseConsumptionError));
|
||||
_payment.StartConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print($"Purchase Failed {result.ResponseCode} {result.DebugMessage}");
|
||||
ShowAlert("Android IAP support is not enabled. Make sure you have enabled 'Custom Build' and installed and enabled the GodotGooglePlayBilling plugin in your Android export settings! This application will not work.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnButton1_pressed()
|
||||
private void ShowAlert(string text)
|
||||
{
|
||||
var result = _googlePlayBilling.Purchase("android.test.canceled");
|
||||
if (result != null && result.Status == (int)Error.Ok)
|
||||
{
|
||||
GD.Print("Purchase Requested");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print($"Purchase Failed {result.ResponseCode} {result.DebugMessage}");
|
||||
}
|
||||
}
|
||||
private void OnButton2_pressed()
|
||||
{
|
||||
var result = _googlePlayBilling.Purchase("android.test.refunded");
|
||||
if (result != null && result.Status == (int)Error.Ok)
|
||||
{
|
||||
GD.Print("Purchase Requested");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print($"Purchase Failed {result.ResponseCode} {result.DebugMessage}");
|
||||
}
|
||||
}
|
||||
private void OnButton3_pressed()
|
||||
{
|
||||
var result = _googlePlayBilling.Purchase("android.test.item_unavailable");
|
||||
if (result != null && result.Status == (int)Error.Ok)
|
||||
{
|
||||
GD.Print("Purchase Requested");
|
||||
}
|
||||
else
|
||||
{
|
||||
GD.Print($"Purchase Failed {result.ResponseCode} {result.DebugMessage}");
|
||||
}
|
||||
_alertDialog.DialogText = text;
|
||||
_alertDialog.PopupCentered();
|
||||
}
|
||||
|
||||
private void OnOkButton_pressed()
|
||||
private void OnConnected()
|
||||
{
|
||||
_panel.Hide();
|
||||
_processLabel.Hide();
|
||||
_thanksLabel.Hide();
|
||||
}
|
||||
GD.Print("PurchaseManager connected");
|
||||
|
||||
private void OnGooglePlayBilling_Connected()
|
||||
{
|
||||
_googlePlayBilling.QuerySkuDetails(ArrInAppProductsSKUs, PurchaseType.InApp);
|
||||
|
||||
var purchasesResult = _googlePlayBilling.QueryPurchases(PurchaseType.InApp);
|
||||
// We must acknowledge all puchases.
|
||||
// See https://developer.android.com/google/play/billing/integrate#process for more information
|
||||
var purchasesResult = _payment.QueryPurchases(PurchaseType.InApp);
|
||||
if (purchasesResult.Status == (int)Error.Ok)
|
||||
{
|
||||
foreach (var purchase in purchasesResult.Purchases)
|
||||
{
|
||||
_purchases.Add(purchase.PurchaseToken, purchase.Sku);
|
||||
// We only expect this SKU
|
||||
if (purchase.Sku == "android.test.purchased")
|
||||
if (!purchase.IsAcknowledged)
|
||||
{
|
||||
_googlePlayBilling.AcknowledgePurchase(purchase.PurchaseToken);
|
||||
GD.Print($"Purchase {purchase.Sku} has not been acknowledged. Acknowledging...");
|
||||
_payment.AcknowledgePurchase(purchase.PurchaseToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,59 +86,105 @@ namespace Android_Iap
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGooglePlayBilling_SkuDetailsQueryCompleted(Godot.Collections.Array arrSkuDetails)
|
||||
private async void OnDisconnected()
|
||||
{
|
||||
var skuDetails = GooglePlayBillingUtils.ConvertSkuDetailsDictionaryArray(arrSkuDetails);
|
||||
foreach (var sku in skuDetails)
|
||||
{
|
||||
switch (sku.Sku)
|
||||
{
|
||||
// our fake potion
|
||||
case "android.test.purchased":
|
||||
_buyPotionButton.Text = $"Buy {sku.Price}";
|
||||
_buyPotionButton.Show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
ShowAlert("GodotGooglePlayBilling disconnected. Will try to reconnect in 10s...");
|
||||
await ToSignal(GetTree().CreateTimer(10), "timeout");
|
||||
_payment.StartConnection();
|
||||
}
|
||||
|
||||
private void OnGooglePlayBilling_PurchasesUpdated(Godot.Collections.Array arrPurchases)
|
||||
private void OnConnectError()
|
||||
{
|
||||
_panel.Show();
|
||||
_processLabel.Show();
|
||||
_thanksLabel.Hide();
|
||||
ShowAlert("PurchaseManager connect error");
|
||||
}
|
||||
|
||||
private void OnPurchasesUpdated(Godot.Collections.Array arrPurchases)
|
||||
{
|
||||
GD.Print($"Purchases updated: {JSON.Print(arrPurchases)}");
|
||||
|
||||
// See OnConnected
|
||||
var purchases = GooglePlayBillingUtils.ConvertPurchaseDictionaryArray(arrPurchases);
|
||||
|
||||
foreach (var purchase in purchases)
|
||||
{
|
||||
_purchases.Add(purchase.PurchaseToken, purchase.Sku);
|
||||
// We only expect this SKU
|
||||
if (purchase.Sku == "android.test.purchased")
|
||||
if (!purchase.IsAcknowledged)
|
||||
{
|
||||
_googlePlayBilling.AcknowledgePurchase(purchase.PurchaseToken);
|
||||
GD.Print($"Purchase {purchase.Sku} has not been acknowledged. Acknowledging...");
|
||||
_payment.AcknowledgePurchase(purchase.PurchaseToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGooglePlayBilling_PurchaseAcknowledged(string purchaseToken)
|
||||
{
|
||||
_googlePlayBilling.ConsumePurchase(purchaseToken);
|
||||
}
|
||||
|
||||
private void OnGooglePlayBilling_PurchaseConsumed(string purchaseToken)
|
||||
{
|
||||
if (_purchases[purchaseToken] == "android.test.purchased")
|
||||
if (purchases.Length > 0)
|
||||
{
|
||||
_totalPotion += 5;
|
||||
_totalPotionsLabel.Text = $"{_totalPotion} Potions";
|
||||
_purchases.Remove(purchaseToken);
|
||||
|
||||
_processLabel.Hide();
|
||||
_thanksLabel.Show();
|
||||
|
||||
_testItemPurchaseToken = purchases.Last().PurchaseToken;
|
||||
}
|
||||
GD.Print("OnGooglePlayBilling_PurchaseConsumed ", purchaseToken);
|
||||
}
|
||||
|
||||
private void OnPurchaseError(int code, string message)
|
||||
{
|
||||
ShowAlert($"Purchase error {code}: {message}");
|
||||
}
|
||||
|
||||
private void OnSkuDetailsQueryCompleted(Godot.Collections.Array arrSkuDetails)
|
||||
{
|
||||
ShowAlert(JSON.Print(arrSkuDetails));
|
||||
|
||||
var skuDetails = GooglePlayBillingUtils.ConvertSkuDetailsDictionaryArray(arrSkuDetails);
|
||||
foreach (var skuDetail in skuDetails)
|
||||
{
|
||||
GD.Print($"Sku {skuDetail.Sku}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSkuDetailsQueryError(int code, string message)
|
||||
{
|
||||
ShowAlert($"SKU details query error {code}: {message}");
|
||||
}
|
||||
|
||||
private void OnPurchaseAcknowledged(string purchaseToken)
|
||||
{
|
||||
ShowAlert($"Purchase acknowledged: {purchaseToken}");
|
||||
}
|
||||
|
||||
private void OnPurchaseAcknowledgementError(int code, string message)
|
||||
{
|
||||
ShowAlert($"Purchase acknowledgement error {code}: {message}");
|
||||
}
|
||||
|
||||
private void OnPurchaseConsumed(string purchaseToken)
|
||||
{
|
||||
ShowAlert($"Purchase consumed successfully: {purchaseToken}");
|
||||
}
|
||||
|
||||
private void OnPurchaseConsumptionError(int code, string message)
|
||||
{
|
||||
ShowAlert($"Purchase acknowledgement error {code}: {message}");
|
||||
}
|
||||
|
||||
// GUI
|
||||
private void OnQuerySkuDetailsButton_pressed()
|
||||
{
|
||||
_payment.QuerySkuDetails(new string[] { TestItemSku }, PurchaseType.InApp); // Use "subs" for subscriptions.
|
||||
}
|
||||
|
||||
private void OnPurchaseButton_pressed()
|
||||
{
|
||||
var response = _payment.Purchase(TestItemSku);
|
||||
if (response != null && response.Status != (int)Error.Ok)
|
||||
{
|
||||
ShowAlert($"Purchase error {response.ResponseCode} {response.DebugMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsumeButton_pressed()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_testItemPurchaseToken))
|
||||
{
|
||||
ShowAlert("You need to set 'test_item_purchase_token' first! (either by hand or in code)");
|
||||
return;
|
||||
}
|
||||
|
||||
_payment.ConsumePurchase(_testItemPurchaseToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://icon.png" type="Texture" id=1]
|
||||
[ext_resource path="res://Main.cs" type="Script" id=2]
|
||||
[ext_resource path="res://GodotGooglePlayBilling/GooglePlayBilling.cs" type="Script" id=3]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 1, 0, 0, 1 )
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=2]
|
||||
bg_color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="Main" type="Node2D"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="GooglePlayBilling" type="Node" parent="."]
|
||||
script = ExtResource( 3 )
|
||||
AutoConnect = true
|
||||
|
||||
[node name="Sprite" type="Sprite" parent="."]
|
||||
position = Vector2( 239.092, 225.037 )
|
||||
scale = Vector2( 2, 2 )
|
||||
texture = ExtResource( 1 )
|
||||
|
||||
[node name="ProgressBar" type="ProgressBar" parent="Sprite"]
|
||||
margin_left = -57.9025
|
||||
margin_top = -47.7944
|
||||
margin_right = 57.0975
|
||||
margin_bottom = -33.7944
|
||||
custom_styles/fg = SubResource( 1 )
|
||||
custom_styles/bg = SubResource( 2 )
|
||||
max_value = 1.0
|
||||
value = 0.5
|
||||
percent_visible = false
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
margin_left = 65.0538
|
||||
margin_top = 30.4056
|
||||
margin_right = 185.054
|
||||
margin_bottom = 88.4056
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||
margin_right = 120.0
|
||||
margin_bottom = 14.0
|
||||
text = "1 Potion"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="UsePotionButton" type="Button" parent="VBoxContainer"]
|
||||
margin_top = 18.0
|
||||
margin_right = 120.0
|
||||
margin_bottom = 58.0
|
||||
rect_min_size = Vector2( 120, 40 )
|
||||
text = "Use Potion"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer2" type="VBoxContainer" parent="."]
|
||||
margin_left = 340.826
|
||||
margin_top = 29.6986
|
||||
margin_right = 460.826
|
||||
margin_bottom = 87.6986
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer2"]
|
||||
margin_right = 121.0
|
||||
margin_bottom = 14.0
|
||||
text = "Get 5 Potions now!"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="BuyPotionButton" type="Button" parent="VBoxContainer2"]
|
||||
margin_top = 18.0
|
||||
margin_right = 121.0
|
||||
margin_bottom = 58.0
|
||||
rect_min_size = Vector2( 120, 40 )
|
||||
text = "Buy"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VBoxContainer3" type="VBoxContainer" parent="."]
|
||||
margin_left = 373.353
|
||||
margin_top = 143.543
|
||||
margin_right = 494.353
|
||||
margin_bottom = 289.543
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer3"]
|
||||
margin_right = 121.0
|
||||
margin_bottom = 14.0
|
||||
text = "Other Items"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Button1" type="Button" parent="VBoxContainer3"]
|
||||
margin_top = 18.0
|
||||
margin_right = 121.0
|
||||
margin_bottom = 58.0
|
||||
rect_min_size = Vector2( 120, 40 )
|
||||
text = "Canceled Item"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Button2" type="Button" parent="VBoxContainer3"]
|
||||
margin_top = 62.0
|
||||
margin_right = 121.0
|
||||
margin_bottom = 102.0
|
||||
rect_min_size = Vector2( 120, 40 )
|
||||
text = "Refunded Item"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Button3" type="Button" parent="VBoxContainer3"]
|
||||
margin_top = 106.0
|
||||
margin_right = 121.0
|
||||
margin_bottom = 146.0
|
||||
rect_min_size = Vector2( 120, 40 )
|
||||
text = "Unavailable Item"
|
||||
__meta__ = {
|
||||
"_edit_lock_": true,
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
visible = false
|
||||
self_modulate = Color( 1, 1, 1, 0.666667 )
|
||||
margin_left = 114.414
|
||||
margin_top = 38.6777
|
||||
margin_right = 379.414
|
||||
margin_bottom = 235.678
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ProcessLabel" type="Label" parent="Panel"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -88.0
|
||||
margin_top = -8.5
|
||||
margin_right = 88.0
|
||||
margin_bottom = 8.5
|
||||
text = "Processing..."
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ThanksLabel" type="Label" parent="Panel"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -88.0
|
||||
margin_top = -8.5
|
||||
margin_right = 88.0
|
||||
margin_bottom = 8.5
|
||||
text = "Thanks for your purchase"
|
||||
align = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="OkButton" type="Button" parent="Panel"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 1.0
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -48.0
|
||||
margin_top = -52.0919
|
||||
margin_right = 48.0
|
||||
margin_bottom = -19.0919
|
||||
text = "Ok"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
[connection signal="Connected" from="GooglePlayBilling" to="." method="OnGooglePlayBilling_Connected"]
|
||||
[connection signal="PurchaseAcknowledged" from="GooglePlayBilling" to="." method="OnGooglePlayBilling_PurchaseAcknowledged"]
|
||||
[connection signal="PurchaseConsumed" from="GooglePlayBilling" to="." method="OnGooglePlayBilling_PurchaseConsumed"]
|
||||
[connection signal="PurchasesUpdated" from="GooglePlayBilling" to="." method="OnGooglePlayBilling_PurchasesUpdated"]
|
||||
[connection signal="SkuDetailsQueryCompleted" from="GooglePlayBilling" to="." method="OnGooglePlayBilling_SkuDetailsQueryCompleted"]
|
||||
[connection signal="pressed" from="VBoxContainer/UsePotionButton" to="." method="OnUsePotionButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer2/BuyPotionButton" to="." method="OnBuyPotionButton_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer3/Button1" to="." method="OnButton1_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer3/Button2" to="." method="OnButton2_pressed"]
|
||||
[connection signal="pressed" from="VBoxContainer3/Button3" to="." method="OnButton3_pressed"]
|
||||
[connection signal="pressed" from="Panel/OkButton" to="." method="OnOkButton_pressed"]
|
||||
@@ -3,7 +3,7 @@ using System.Reflection;
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("Android IAP with C#")]
|
||||
[assembly: AssemblyTitle("Android in-app purchases with C#")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
# Android IAP with C#
|
||||
|
||||
A simple Android IAP game. This demo shows how to buy a product and consume it for game development in Godot, including
|
||||
[Android in-app purchases](https://docs.godotengine.org/en/latest/tutorials/platform/android_in_app_purchases.html).
|
||||
These demos depend on features only available in mobile phones or tablets.
|
||||
|
||||
The Android IAP demo only runs on Android.
|
||||
|
||||
Language: [C#](https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html)
|
||||
|
||||
Renderer: GLES 2
|
||||
|
||||
Note: There is a GDScript version available, but it's a bit simpler [here](https://github.com/godotengine/godot-demo-projects/tree/master/mobile/android_iap).
|
||||
|
||||
## How does it work?
|
||||
|
||||
You have to use potions to heal the fake Player and you have only 5 potions left, you can just buy more to keep healing the Player. The purchase is fake and won't charge anything, it uses the fake ids provided by Google.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
Note: There is a GDScript version available [here](https://github.com/godotengine/godot-demo-projects/tree/master/mobile/AndroidInAppPurchasesWithCSharp).
|
||||
|
||||
87
mono/android_iap/main.tscn
Normal file
87
mono/android_iap/main.tscn
Normal file
@@ -0,0 +1,87 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://Main.cs" type="Script" id=1]
|
||||
[ext_resource path="res://GodotGooglePlayBilling/GooglePlayBilling.cs" type="Script" id=2]
|
||||
|
||||
[node name="Main" type="Control"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -512.711
|
||||
margin_top = -300.0
|
||||
margin_right = 511.289
|
||||
margin_bottom = 300.0
|
||||
size_flags_horizontal = 2
|
||||
size_flags_vertical = 2
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="AlertDialog" type="AcceptDialog" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = 64.0
|
||||
margin_top = 64.0
|
||||
margin_right = -64.0
|
||||
margin_bottom = -64.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
rect_min_size = Vector2( 400, 0 )
|
||||
size_flags_vertical = 4
|
||||
popup_exclusive = true
|
||||
dialog_autowrap = true
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
margin_left = 300.0
|
||||
margin_top = 40.0
|
||||
margin_right = 996.0
|
||||
margin_bottom = 156.0
|
||||
size_flags_horizontal = 2
|
||||
size_flags_vertical = 0
|
||||
text = "To test in-app purchase on android device,
|
||||
|
||||
1. Make sure you have enabled \"Custom Build\" and the GodotPayment plugin in your Android export settings
|
||||
2. Export APK and upload it as alpha or beta stage to Google Play Developer Console and publish it.
|
||||
(It's not published to public, but you and other testers can access it.)
|
||||
3. There should be an activate in-app item. Copy its SKU into the TEST_ITEM_SKU constant in iap_demo.gd
|
||||
4. Changes you make in the Play Console may take some time before taking effect"
|
||||
|
||||
[node name="QuerySkuDetailsButton" type="Button" parent="."]
|
||||
margin_left = 40.5697
|
||||
margin_top = 39.9347
|
||||
margin_right = 221.57
|
||||
margin_bottom = 91.9347
|
||||
text = "Query SKU details"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="PurchaseButton" type="Button" parent="."]
|
||||
margin_left = 40.5697
|
||||
margin_top = 101.203
|
||||
margin_right = 221.57
|
||||
margin_bottom = 153.203
|
||||
text = "Purchase"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ConsumeButton" type="Button" parent="."]
|
||||
margin_left = 40.5697
|
||||
margin_top = 162.142
|
||||
margin_right = 221.57
|
||||
margin_bottom = 214.142
|
||||
text = "Consume"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="GooglePlayBilling" type="Node" parent="."]
|
||||
script = ExtResource( 2 )
|
||||
[connection signal="pressed" from="QuerySkuDetailsButton" to="." method="OnQuerySkuDetailsButton_pressed"]
|
||||
[connection signal="pressed" from="PurchaseButton" to="." method="OnPurchaseButton_pressed"]
|
||||
[connection signal="pressed" from="ConsumeButton" to="." method="OnConsumeButton_pressed"]
|
||||
@@ -15,21 +15,24 @@ _global_script_class_icons={
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Android IAP with C#"
|
||||
config/description="A simple Android IAP game. This demo shows how to buy a product and consume it."
|
||||
run/main_scene="res://Main.tscn"
|
||||
config/name="Android in-app purchases with C#"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[debug]
|
||||
|
||||
gdscript/warnings/return_value_discarded=false
|
||||
|
||||
[display]
|
||||
|
||||
window/size/width=512
|
||||
window/size/height=300
|
||||
window/stretch/mode="2d"
|
||||
window/stretch/aspect="keep"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[gdnative]
|
||||
|
||||
singletons=[ ]
|
||||
|
||||
[rendering]
|
||||
|
||||
quality/driver/driver_name="GLES2"
|
||||
vram_compression/import_etc=true
|
||||
vram_compression/import_etc2=false
|
||||
environment/default_environment="res://default_env.tres"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB |
Reference in New Issue
Block a user