I am trying to add In-app purchases to my app. I tried to create StoreKit Configuration File but after checking "Sync this file with an app in App Store Connect" I wanted to pick my team but the only options I had were "None" or "Ad an account...". And answering upcoming question: Yes I have team. Please help.
Post
Replies
Boosts
Views
Activity
I am making an app in SwiftUI using an In-app purchase. In this app, the user should be able to buy points as many times as he wants, so I have used consumable products (in the app store connect). But when I've tried to buy them once again I got the information "This In-App purchase has already been bought. It will be restored for free". I've already searched for a way how to do it but none of the ideas worked for me.
Here is my StoreManager class:
import Foundation
import StoreKit
import SwiftUI
class StoreManager : NSObject, ObservableObject, SKProductsRequestDelegate {
@EnvironmentObject var authViewModel: AuthViewModel
@Published var transactionState: SKPaymentTransactionState?
@Published var myProducts = [SKProduct]()
var request: SKProductsRequest!
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Did receive response")
if !response.products.isEmpty {
for fetchedProduct in response.products {
DispatchQueue.main.async {
self.myProducts.append(fetchedProduct)
}
}
for invalidIdentifier in response.invalidProductIdentifiers {
print("Invalid identifiers found: \(invalidIdentifier)")
}
}else{
print("it's empty")
}
}
func getProducts(productIDs: [String]) {
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
request.delegate = self
request.start()
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Request did fail: \(error)")
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
transactionState = .purchasing
break
case .purchased:
print("purchased")
queue.finishTransaction(transaction)
transactionState = .purchased
break
case .restored:
print("restored")
transactionState = .restored
queue.finishTransaction(transaction)
break
case .failed, .deferred:
queue.finishTransaction(transaction)
transactionState = .failed
break
default:
queue.finishTransaction(transaction)
break
}
}
}
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func restoreProducts() {
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
And I am simply using getProducts with onAppear, and purchase product on button's action.
Please help me or if an answer to a similar question already exists send me a link to that thread.
Hi I am trying to create app on watchOS using swiftUI. This app would simply check temperature of the water or other place user will actually be (e.g. Sauna). My question is: Is there any way I can achieve that for all Apple Watch models and not only Ultra? If there is, I would be thankful for some documentation, I couldn't find anything helpful.
I am making family tree app and I need to create possibility to zoom in scrollview. I've tried few solutions but none of them work for me. I will have a lot of content going out of the screen and I need to be able to zoom out, and then be able to start from the last position. Here is my test view:
struct Test: View {
@State var scale: CGFloat = 1.0
@State var lastScaleValue: CGFloat = 1.0
var body: some View {
ScrollView([.horizontal, .vertical]){
VStack(spacing: 100){
ForEach(1..<10){ i in
Text("Number \(i)")
.onTapGesture {
// center item
}
.padding(.leading, Double(i)*50)
}
ForEach(1..<10){ i in
Text("Number \(i)")
.onTapGesture {
// center item
}
.padding(.trailing, Double(i)*50)
}
}//.pinchToZoom()
}
}
}
Here is pinchToZoom which is not working as I want to
class PinchZoomView: UIView {
weak var delegate: PinchZoomViewDelgate?
private(set) var scale: CGFloat = 0 {
didSet {
delegate?.pinchZoomView(self, didChangeScale: scale)
}
}
private(set) var anchor: UnitPoint = .center {
didSet {
delegate?.pinchZoomView(self, didChangeAnchor: anchor)
}
}
private(set) var offset: CGSize = .zero {
didSet {
delegate?.pinchZoomView(self, didChangeOffset: offset)
}
}
private(set) var isPinching: Bool = false {
didSet {
delegate?.pinchZoomView(self, didChangePinching: isPinching)
}
}
private var startLocation: CGPoint = .zero
private var location: CGPoint = .zero
private var numberOfTouches: Int = 0
init() {
super.init(frame: .zero)
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinch(gesture:)))
pinchGesture.cancelsTouchesInView = false
addGestureRecognizer(pinchGesture)
}
required init?(coder: NSCoder) {
fatalError()
}
@objc private func pinch(gesture: UIPinchGestureRecognizer) {
switch gesture.state {
case .began:
isPinching = true
startLocation = gesture.location(in: self)
numberOfTouches = gesture.numberOfTouches
case .changed:
if gesture.numberOfTouches != numberOfTouches {
let newLocation = gesture.location(in: self)
let jumpDifference = CGSize(width: newLocation.x - location.x, height: newLocation.y - location.y)
startLocation = CGPoint(x: startLocation.x + jumpDifference.width, y: startLocation.y + jumpDifference.height)
numberOfTouches = gesture.numberOfTouches
}
scale = gesture.scale
location = gesture.location(in: self)
offset = CGSize(width: location.x - startLocation.x, height: location.y - startLocation.y)
case .ended, .cancelled, .failed:
isPinching = false
default:
break
}
}
}
protocol PinchZoomViewDelgate: AnyObject {
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangePinching isPinching: Bool)
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeScale scale: CGFloat)
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeAnchor anchor: UnitPoint)
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeOffset offset: CGSize)
}
struct PinchZoom: UIViewRepresentable {
@Binding var scale: CGFloat
@Binding var anchor: UnitPoint
@Binding var offset: CGSize
@Binding var isPinching: Bool
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> PinchZoomView {
let pinchZoomView = PinchZoomView()
pinchZoomView.delegate = context.coordinator
return pinchZoomView
}
func updateUIView(_ pageControl: PinchZoomView, context: Context) { }
class Coordinator: NSObject, PinchZoomViewDelgate {
var pinchZoom: PinchZoom
init(_ pinchZoom: PinchZoom) {
self.pinchZoom = pinchZoom
}
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangePinching isPinching: Bool) {
pinchZoom.isPinching = isPinching
}
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeScale scale: CGFloat) {
pinchZoom.scale = scale
}
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeAnchor anchor: UnitPoint) {
pinchZoom.anchor = anchor
}
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeOffset offset: CGSize) {
pinchZoom.offset = offset
}
}
}
struct PinchToZoom: ViewModifier {
@State var scale: CGFloat = 1.0
@State var anchor: UnitPoint = .center
@State var offset: CGSize = .zero
@State var isPinching: Bool = false
func body(content: Content) -> some View {
content
.scaleEffect(scale, anchor: anchor)
.offset(offset)
.animation(isPinching ? .none : .spring())
.overlay(PinchZoom(scale: $scale, anchor: $anchor, offset: $offset, isPinching: $isPinching))
}
}
extension View {
func pinchToZoom() -> some View {
self.modifier(PinchToZoom())
}
}