Skip to content

Instantly share code, notes, and snippets.

@HelloNamiML
HelloNamiML / storekit2_verify_purchase.swift
Created June 11, 2021 21:34
StoreKit 2: Verify a purchase on-device
let result = await Transaction.latest(for: "myProductID")
switch result {
case .unverified:
// StoreKit has parsed the JWS but failed verification. Don't deliver content to the user.
throw StoreError.failedVerification
case .verified(let safe):
// If the transaction is verified, unwrap and return it.
return safe
}
@HelloNamiML
HelloNamiML / appleResponseBody.json
Last active March 2, 2024 21:32
App Store Decoded Receipt Response Body
{
"environment": "Sandbox",
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "com.namiml.NamiRadio",
"application_version": "25",
"download_id": 0,
"version_external_identifier": 0,
@HelloNamiML
HelloNamiML / useArgumentResetStorage.swift
Created November 5, 2021 04:18
Use command line argument to reset app storage
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if ProcessInfo.processInfo.arguments.contains("CLEANSTART") {
// Call internal method to clear existing application storage
resetApplicationStorage()
}
}
@HelloNamiML
HelloNamiML / testLaunchArguments.swift
Created November 5, 2021 04:17
Add arguments to launch app with cleared storage
func testCallFlowFirstStart() {
// Re-launch the app with an argument to clear out storage
let app = XCUIApplication()
app.launchArguments.append("CLEANSTART")
app.launch()
// Rest of your test case follows....
}
@HelloNamiML
HelloNamiML / testPurchasePressed.swift
Created November 5, 2021 04:15
Move a unit test to a ui test
@IBAction func testPurchasePressed(_ sender: Any) {
NamiPurchaseManager.skusForSKUIDs(skuIDs: ["test_product_id"], productHandler: { (_, products, _, error) in
// We make sure StoreKit can load the product we intend to purchase.
if let products = products, let product = products.first {
// Tell the Nami SDK to initiate a purchase via StoreKit.
NamiPurchaseManager.buySKU(product, responseHandler: { (purchases, _, _) in
if purchases.count > 0 {
// Success
DispatchQueue.main.async {
// Make the result available in both the text of the label and the accessibilityValue
@HelloNamiML
HelloNamiML / testPurchaseLabel.swift
Created November 5, 2021 04:14
Display a button with a result of a ui test
override func viewDidLoad() {
super.viewDidLoad()
self.transactionSentLabel?.accessibilityIdentifier = "purchaseResultLabel"
// Make the result available in both the text of the label and the accessibilityValue
self.transactionSentLabel?.text = "none"
self.transactionSentLabel?.accessibilityValue = "none"
}
@HelloNamiML
HelloNamiML / testPurchase.swift
Created November 5, 2021 04:11
UI Test making a StoreKit purchase
class UnitTestingAppUITests: XCTestCase {
func testPurchase() {
// Make sure to use the StoreKit configuration file that Xcode supports for testing purchases.
if let session = try? SKTestSession(configurationFileNamed: "UnitTestStoreKitConfig.storekit") {
session.disableDialogs = true
session.clearTransactions()
}
@HelloNamiML
HelloNamiML / storekit2_purchase_product.swift
Created June 11, 2021 21:31
StoreKit 2: Purchase Product
let result = try await storeProducts.first.purchase()
@HelloNamiML
HelloNamiML / storekit2_get_product.swift
Created June 11, 2021 20:25
StoreKit 2: Get Product
let storeProducts = try await Product.request(with: Set("myProductID"))
@HelloNamiML
HelloNamiML / AppStoreReceipt
Created August 9, 2020 19:51
An example of a Base64 encoded Apple App Store receipt
MIJF9wYJKoZIhvcNAQcCoIJF6DCCReQCAQExCzAJBgUrDgMCGgUAMII1mAYJKoZIhvcNAQcBoII1iQSCNYUxgjWBMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIBDwIBAQQDAgEAMAsCARACAQEEAwIBADALAgEZAgEBBAMCAQMwDAIBAwIBAQQEDAIyNTAMAgEKAgEBBAQWAjQrMAwCAQ4CAQEEBAICAM8wDQIBDQIBAQQFAgMCIuAwDQIBEwIBAQQFDAMxLjAwDgIBCQIBAQQGAgRQMjU1MBgCAQQCAQIEEBE8i4A67jeWmcZBUG0nziswGwIBAAIBAQQTDBFQcm9kdWN0aW9uU2FuZGJveDAcAgEFAgEBBBRXmxfahuClkpJtx6E9Xn/ABWf8RTAeAgEMAgEBBBYWFDIwMjAtMDctMjNUMTk6MzI6NTFaMB4CARICAQEEFhYUMjAxMy0wOC0wMVQwNzowMDowMFowKwIBAgIBAQQjDCFjb20ubmFtaS5tYXR0aGV3ZmVjaGVyLlN3aWZ0UmFkaW8wQQIBBgIBAQQ5rfixfh+FERqFNSCsR6oweYr2yLPoPcWXb+1l5R+y6iljrQK4QeD/70rMSCnjqMUtABXUn6ljNgX8ME0CAQcCAQEERb8OuF+8oUgd4tX5dCj5RaqEVA+E0uoR+TfMoFc9FiHuaLRPvVQpQ+DQh5lZXuxjeh3wUQh5lWou27kDJLl9P9KGpB0YZDCCAYsCARECAQEEggGBMYIBfTALAgIGrQIBAQQCDAAwCwICBrACAQEEAhYAMAsCAgayAgEBBAIMADALAgIGswIBAQQCDAAwCwICBrQCAQEEAgwAMAsCAga1AgEBBAIMADALAgIGtgIBAQQCDAAwDAICBqUCAQEEAwIBATAMAgIGqwIBAQQDAgEDMAwCAgauAgEBBAMCAQAwDAICBrECAQEEAwIBADAMAgIGtwIBAQQDAgEAMBICAgav