Question

I'm updating my app due to an App Store rejection of binary because my app contains links to websites in the "credit" page. I need to implement a parental gate to restrict access to "credit" view controller.

I have found a code that checks permission for in-app purchase. But I guess I cannot use the same for this purpose?

How do I check parental permission before opening a view controller?

Était-ce utile?

La solution

I've posted an open source Parental Gate SDK which has been used in an app that has successfully passed review under Apple's new 24.3 rule that requires a "parental gate" for in app purchases and anything that brings the user experience to the web. You can read more about the SDK and get the code here:

MKParentalGate Open Source SDK

Autres conseils

My Application was rejected for same reason . I added Parental gateway on App upgrade but I had advertisement in my app that hence it was rejected again as tapping advertisement leaves application and open itune stores. I am not sure if anyone can ask parental question after tapping advertisement and before opening external link.

I see two solution 1. Remove advertisement from app 2. Deselect Made for Kids

Does it mean that we can not have advertisement for apps made for Kids?

I've just recently talked with Apple about this.

Firstly, they're going to leave this to developers to implement without necessarily telling us what they're going to accept. However, I did manage to get from Apple that it's really dependent upon the age group that you're targeting too. If you're going for an older age group the parental gate must be harder to overcome.

A simple pop up telling the user that it's adults only after that point won't do. There has to be something else which stops the user. Multi-touch swipes, maths questions, and history questions were suggested as being acceptable.

My worry is that I know a lot of parents who couldn't do the simple arithmetic operations that I've seen being used in some (45+62 etc). History questions would be difficult as the history of my country is different from yours (When was the battle of Bannockburn?). One way around this that I've seen is to give multiple choice answers, but with three options there's a 33% chance of guesswork being sufficient! Multi touch swipes is too easy.

Ideally this really should be covered by Apple as part of iOS requiring the passcode. At least it would standardise parental gates.

I've put in a parental gate based upon picking one of four options as asked with a second row of options and a different question. What I'm aiming to do here is to keep the quiz easy enough for the parents but at the same time unlikely that a random guess would solve the puzzle. Four options is 25% chance of being right and that reduced to 6% with the second question. I think this will work for my target at the younger end of the requirements.

** My version of a parental gate was accepted. From the first view controller I'd call the parental gate. If failed it would dismiss and create a UIAlertView stating it failed. If it passed then it would also dismiss and send a notification of success on completion. The calling view controller receives the notification and then does whatever it would have done if it hadn't had to do a parental gate!

Given that there still seems to be a lot of uncertainty around this I thought I'd share my own experiences.

Because I make apps for young children (up to age six or something like that), I can assume that the parental gate doesn't need to be too difficult. At the moment I implemented a simple UIAlertView that asks a math question. Because of the comment made in one of the other answers I'm actually in the process of making that question a little simpler.

What I'm doing is taking two random numbers between 10 and 30 and requesting the user to add those and type in the answer. Unfortunately because I'm doing this in a UIAlertView at the moment and I need an edit field, this raises the bar for iOS use to 5.0. Looking at the Flurry data for my apps, over the last month anything under iOS 5 barely registered (less than 1% of the total) so I'm not too concerned about that.

I'm still considering whether I can't make this simpler for adults but not necessarily for children by building on what we have learned about math. Making sure for example that any number to be added is even, would probably make it easier for many people. Working with multiple's of five would make it easier still while I don't think children have learned those tricks at all so it wouldn't make much difference for them.

I have three different apps in the App Store using this same approach and they got all accepted, even though they got reviewed by different people (I can tell by how stupidly different their decisions on other points are) so I'm assuming this approach is sanctioned. What I haven't done yet is tried to come up with a way to judge whether this is found annoying by users or whether most people can deal with this without too much worry.

You may want to try this cocoapod library: https://cocoapods.org/pods/HYParentalGate

I created one with swiftUI for this who need it.

It generates 3 random numbers and then asks you to press the number buttons in that order, if correct it hides the gate with opacity so I use it on a screen that needs the gate as it loads so when the gate hides, it shows the other view underneath. If the numbers pressed are incorrect, it closes the gate and dismiss the view back to the original view.

Parent Gate

import SwiftUI

struct GateScreen: View {
@Environment(\.presentationMode) var presentationMode
@State var tInput1 = "1"
@State var tInput2 = "2"
@State var tInput3 = "3"
@State var nP = ""
@State var npP = ""
@State var pressedN  = ""
@State var randN = 0
@State var showingAbout = false
@State var hiddenOpp = 1.0


var body: some View {
    ZStack {
        Color(.white)
    VStack {
        Capsule()
         .fill(Color.gray)
       .frame(width: 80, height: 5)
            .padding(.vertical)
        Spacer()
        Text("""
            This area is for parents only.
            Please press the numbers shown, in order.
            """)
            .padding()
            .font(.system(size: 20))
            .multilineTextAlignment(.center)
            .frame(width: 400)
        Spacer()
        HStack {
            Text(tInput1)
                .font(.system(size: 30))
                .frame(width: 40, height: 40, alignment: .center)
                .overlay(
                        RoundedRectangle(cornerRadius: 16)
                            .stroke(Color.black, lineWidth: 2)
                    )
                .multilineTextAlignment(.center)
                
            Text(tInput2)
                .font(.system(size: 30))
                .frame(width: 40, height: 40, alignment: .center)
                .overlay(
                        RoundedRectangle(cornerRadius: 16)
                            .stroke(Color.black, lineWidth: 2)
                    )
                .multilineTextAlignment(.center)
            
            Text(tInput3)
                .font(.system(size: 30))
                .frame(width: 40, height: 40, alignment: .center)
                .overlay(
                        RoundedRectangle(cornerRadius: 16)
                            .stroke(Color.black, lineWidth: 2)
                    )
                .multilineTextAlignment(.center)
        }
        .padding()
        Spacer()
            HStack {
                Group {

                    Button(action: {
                       pressedN = "0"
                        numbersPressed()
                    }) {
                        Text("0")
                            .font(.system(size: 20))
                                            .fontWeight(.heavy)
                                            .foregroundColor(Color.blue)
                                            .multilineTextAlignment(.center)
                                            .padding(20.0)
                                            .overlay(
                                                    RoundedRectangle(cornerRadius: 16)
                                                        .stroke(Color.blue, lineWidth: 4)
                                                )
                            
                    }
                    Button(action: {
                        pressedN = "1"
                        numbersPressed()
                    }) {
        Text("1")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
            }
         
                    Button(action: {
                        pressedN = "2"
                        numbersPressed()
                    }) {
        Text("2")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                    }
                    Button(action: {
                        pressedN = "3"
                        numbersPressed()
                    }) {
        Text("3")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                    }
                    Button(action: {
                        pressedN = "4"
                        numbersPressed()
                    }) {
        Text("4")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                    }
            }
        }
        HStack {
            Group {
                Button(action: {
                    pressedN = "5"
                    numbersPressed()
                }) {
        Text("5")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                }
                Button(action: {
                    pressedN = "6"
                    numbersPressed()
                }) {
        Text("6")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                }
                Button(action: {
                    pressedN = "7"
                    numbersPressed()
                }) {
        Text("7")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                }
                Button(action: {
                    pressedN = "8"
                    numbersPressed()
                }) {
        Text("8")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                }
                Button(action: {
                    pressedN = "9"
                    numbersPressed()
                }) {
        Text("9")
            .font(.system(size: 20))
            .fontWeight(.heavy)
            .foregroundColor(Color.blue)
            .multilineTextAlignment(.center)
            .padding(20.0)
            .overlay(
                    RoundedRectangle(cornerRadius: 16)
                        .stroke(Color.blue, lineWidth: 4)
                )
                }
                }
            }
        Spacer()
        }
    }
    .opacity(hiddenOpp)
    .onAppear() {
       setNums()
        
    }
}

func setNums() {
    for _ in 0..<3 {
    randN = Int.random(in: 0..<10)
        npP = npP + "\(randN)"
    print("Tony numbers are \(npP)")
}
    let char1 = npP[npP.index(npP.startIndex, offsetBy: 0)]
        tInput1 = "\(char1)"
    
   let char2 = npP[npP.index(npP.startIndex, offsetBy: 1)]
        tInput2 = "\(char2)"
    
    let char3 = npP[npP.index(npP.startIndex, offsetBy: 2)]
        tInput3 = "\(char3)"
}

func numbersPressed(){
    if nP == "" {
        nP = pressedN
        print("Tony numbers are \(nP)")
    }else {
        if nP.count == 1 {
        nP = nP + pressedN
            print("Tony numbers are \(nP)")
    }else {
        nP = nP + pressedN
        print("Tony numbers are \(nP)")
        if nP == "\(npP)" {
            npP = ""
            nP = ""
            print("Tony Corect numbers")
                hiddenOpp = 0.0
        }else {
            self.presentationMode.wrappedValue.dismiss()
           print("Tony Incorect numbers")
            npP = ""
            nP = ""
            setNums()
        }
    }
}
}


}

Here's one I made today. I haven't gotten a response from Apple yet. It has passed app review

enter image description here

import SwiftUI

struct Triangle: Shape {
    func path(in rect: CGRect) -> Path {
        var path = Path()

        path.move(to: CGPoint(x: rect.midX, y: rect.minY))
        path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        path.addLine(to: CGPoint(x: rect.midX, y: rect.minY))

        return path
    }
}

struct ParentalGateView: View {

    // MARK: - Properties
    var onClose: (() -> Void)?
    var onCancel: (() -> Void)?
    @State private var circleTapped: Bool = false

    // MARK: - UI Layout
    var body: some View {
        VStack(alignment: .center, spacing: 60) {
            HStack {
                Image(systemName: "arrow.left")
                    .resizable()
                    .frame(width: 40, height: 33)
                    .foregroundColor(.red)
                    .onTapGesture {
                        HapticEngine.select.selectionChanged()
                        onCancel?()
                    }
                Spacer()
            }.padding([.leading, .top], 24)

            Text("Ask your parents")
                .font(.largeTitle)
                .fontWeight(.black)
                .foregroundColor(.blue)

            Spacer()
            HStack(spacing: 130) {
                Button("") {}
                .background(Triangle()
                                .foregroundColor(.green)
                                .frame(width: 100, height: 100)
                                .onTapGesture { !circleTapped ? onCancel?() : print("") }
                                .onLongPressGesture { circleTapped ? onClose?() : onCancel?() })

                Button("") {}
                .background(Rectangle()
                                .foregroundColor(.blue)
                                .frame(width: 100, height: 100))
                                .onTapGesture { onCancel?() }

                Button("") {}
                .background(Circle()
                                .foregroundColor(circleTapped ? .green : .yellow)
                                .frame(width: 100, height: 100)
                                .animation(.easeInOut)
                                .onTapGesture(count: 4) { circleTapped = true })
            }.padding()

            Text("Tap inside the circle until the circle turns green, then hold triangle.")
                .multilineTextAlignment(.center)
                .font(.headline)
                .padding([.leading, .trailing], 16)
                .foregroundColor(.orange)
            Spacer()
        }
    }
}

struct ParentalGateView_Previews: PreviewProvider {
    static var previews: some View {
        ParentalGateView()
            .preferredColorScheme(.dark)
    }
}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top