IAPing.
34
desktop/src-common/advent/iap.clj
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
(ns advent.iap
|
||||||
|
(:import [com.badlogic.gdx Gdx Application])
|
||||||
|
(:require [clojure.core.async :as a]
|
||||||
|
[advent.utils :as utils]))
|
||||||
|
|
||||||
|
(def purchase-chan (a/chan 1))
|
||||||
|
(def has-purchased? (atom false))
|
||||||
|
(def can-purchase? (atom false))
|
||||||
|
|
||||||
|
(defn set-purchase-pref [val]
|
||||||
|
(println "setting preference purchased:" val)
|
||||||
|
(let [prefs (.getPreferences (Gdx/app) "purchases")]
|
||||||
|
(.putBoolean prefs "has-purchased?" val)
|
||||||
|
(.flush prefs))
|
||||||
|
(reset! has-purchased? val)
|
||||||
|
(a/go (a/>! purchase-chan val)))
|
||||||
|
|
||||||
|
(defn check-purchase-pref []
|
||||||
|
(let [prefs (.getPreferences (Gdx/app) "purchases")]
|
||||||
|
(if (.contains prefs "has-purchased?")
|
||||||
|
(.getBoolean prefs "has-purchased?")
|
||||||
|
false)))
|
||||||
|
|
||||||
|
(defn use-pref []
|
||||||
|
(swap! has-purchased? #(or % (check-purchase-pref)))
|
||||||
|
(println "preferences purchased:" @has-purchased?))
|
||||||
|
|
||||||
|
(defn start-purchase []
|
||||||
|
(utils/platformify
|
||||||
|
(do
|
||||||
|
(require '[advent.ios])
|
||||||
|
(@(resolve 'advent.ios/start-purchase)) )
|
||||||
|
(.triggerPurchase (Gdx/app))
|
||||||
|
(set-purchase-pref true)))
|
||||||
BIN
ios/resources/Icon-1024x1024.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/1024x1024.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/29x29.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/29x29@2x-1.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/29x29@2x.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/29x29@3x.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
116
ios/resources/Images.xcassets/AppIcon.appiconset/Contents.json
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "icon-large20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "icon-large20x20@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "29x29@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "icon-large40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "icon-large40x40@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-60@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-60@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large20x20.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large20x20@2x-1.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "29x29.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "29x29@2x-1.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large40x40.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large40x40@2x-1.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large76x76.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "icon-large76x76@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-83.5@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "1024x1024.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 25 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon-76.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 13 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
ios/resources/Images.xcassets/AppIcon.appiconset/Icon@2x.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
6
ios/resources/Images.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
55
ios/src/clojure/advent/ios.clj
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
(ns advent.ios
|
||||||
|
(:require [advent.iap :as iap])
|
||||||
|
(:import [org.robovm.apple.storekit SKProductsResponse SKProduct SKMutablePayment SKPaymentQueue SKPaymentTransactionState]))
|
||||||
|
|
||||||
|
(def product (atom nil))
|
||||||
|
|
||||||
|
(defn products-did-receive-response [request ^SKProductsResponse response]
|
||||||
|
(reset! iap/can-purchase? true)
|
||||||
|
(reset! product (first (seq (.toArray (.getProducts response))))))
|
||||||
|
|
||||||
|
(defn products-did-fail [request error]
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn products-did-finish [request]
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn start-purchase []
|
||||||
|
(try
|
||||||
|
(.addPayment (SKPaymentQueue/getDefaultQueue)
|
||||||
|
(doto (SKMutablePayment. @product)
|
||||||
|
(.setQuantity 1)))
|
||||||
|
(catch Exception e
|
||||||
|
(println e))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn updated-transactions [queue, transactions]
|
||||||
|
|
||||||
|
(let [purchased-states #{SKPaymentTransactionState/Purchased SKPaymentTransactionState/Restored}
|
||||||
|
finished-states #{SKPaymentTransactionState/Purchased SKPaymentTransactionState/Restored SKPaymentTransactionState/Failed SKPaymentTransactionState/Deferred}
|
||||||
|
is-finished (->> transactions
|
||||||
|
.toArray
|
||||||
|
seq
|
||||||
|
(every? #(finished-states (.getTransactionState %))))
|
||||||
|
|
||||||
|
has-purchased (->> transactions
|
||||||
|
.toArray
|
||||||
|
seq
|
||||||
|
(filter #(purchased-states (.getTransactionState %)))
|
||||||
|
(map #(-> % (.getPayment) (.getProductIdentifier)))
|
||||||
|
(filter #(= % "fullgame"))
|
||||||
|
seq)]
|
||||||
|
(when is-finished
|
||||||
|
(iap/set-purchase-pref (if has-purchased true false))
|
||||||
|
(doseq [^SKPaymentTransaction trans (->> transactions .toArray seq)]
|
||||||
|
(.finishTransaction (SKPaymentQueue/getDefaultQueue) trans)))))
|
||||||
|
|
||||||
|
(defn updated-downloads [queue, downloads]
|
||||||
|
(println "updated downloads" downloads))
|
||||||
|
(defn restore-completed-transactions-finished [queue]
|
||||||
|
(println "transactions finished"))
|
||||||
|
(defn restore-completed-transactions-failed [queue, error]
|
||||||
|
(println "transactions failed"))
|
||||||
|
(defn removed-transactions [queue, transactions]
|
||||||
|
(println "transactions removed" transactions))
|
||||||
33
ios/src/java/advent/core/ProductDelegate.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package advent.core;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import clojure.lang.RT;
|
||||||
|
import clojure.lang.Symbol;
|
||||||
|
import clojure.lang.IFn;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.*;
|
||||||
|
import com.badlogic.gdx.backends.iosrobovm.*;
|
||||||
|
|
||||||
|
import org.robovm.apple.foundation.*;
|
||||||
|
import org.robovm.apple.uikit.UIApplication;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableColorFormat;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableDepthFormat;
|
||||||
|
import org.robovm.apple.storekit.*;
|
||||||
|
|
||||||
|
public class ProductDelegate extends SKProductsRequestDelegateAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didReceiveResponse(SKProductsRequest request, SKProductsResponse response) {
|
||||||
|
((IFn) RT.var("advent.ios", "products-did-receive-response").deref()).invoke(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didFail(SKRequest request, NSError error) {
|
||||||
|
((IFn) RT.var("advent.ios", "products-did-fail").deref()).invoke(request, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void didFinish(SKRequest request) {
|
||||||
|
((IFn) RT.var("advent.ios", "products-did-finish").deref()).invoke(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
43
ios/src/java/advent/core/TransactionObserver.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package advent.core;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import clojure.lang.RT;
|
||||||
|
import clojure.lang.Symbol;
|
||||||
|
import clojure.lang.IFn;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.*;
|
||||||
|
import com.badlogic.gdx.backends.iosrobovm.*;
|
||||||
|
|
||||||
|
import org.robovm.apple.foundation.*;
|
||||||
|
import org.robovm.apple.uikit.UIApplication;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableColorFormat;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableDepthFormat;
|
||||||
|
import org.robovm.apple.storekit.*;
|
||||||
|
|
||||||
|
public class TransactionObserver extends SKPaymentTransactionObserverAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatedTransactions(SKPaymentQueue queue, NSArray<SKPaymentTransaction> transactions) {
|
||||||
|
((IFn) RT.var("advent.ios", "updated-transactions").deref()).invoke(queue, transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updatedDownloads(SKPaymentQueue queue, NSArray<SKDownload> downloads) {
|
||||||
|
((IFn) RT.var("advent.ios", "updated-downloads").deref()).invoke(queue, downloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreCompletedTransactionsFinished(SKPaymentQueue queue) {
|
||||||
|
((IFn) RT.var("advent.ios", "restore-completed-transactions-finished").deref()).invoke(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreCompletedTransactionsFailed(SKPaymentQueue queue, NSError error) {
|
||||||
|
((IFn) RT.var("advent.ios", "restore-completed-transactions-failed").deref()).invoke(queue, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removedTransactions(SKPaymentQueue queue, NSArray<SKPaymentTransaction> transactions) {
|
||||||
|
((IFn) RT.var("advent.ios", "removed-transactions").deref()).invoke(queue, transactions);
|
||||||
|
}
|
||||||
|
}
|
||||||