由于 App Store 拒绝二进制文件,我正在更新我的应用程序,因为我的应用程序在“信用”页面中包含指向网站的链接。我需要实现一个家长门来限制对“信用”视图控制器的访问。
我找到了一个检查应用内购买权限的代码。但我想我不能为此目的使用相同的?
在打开视图控制器之前如何检查父母的许可?
由于 App Store 拒绝二进制文件,我正在更新我的应用程序,因为我的应用程序在“信用”页面中包含指向网站的链接。我需要实现一个家长门来限制对“信用”视图控制器的访问。
我找到了一个检查应用内购买权限的代码。但我想我不能为此目的使用相同的?
在打开视图控制器之前如何检查父母的许可?
我发布了一个开源的 Parental Gate SDK,该 SDK 已在一个应用程序中使用,该应用程序已成功通过 Apple 新的 24.3 规则的审查,该规则要求应用程序内购买的“家长门”以及任何将用户体验带入网络的东西。您可以阅读有关 SDK 的更多信息并在此处获取代码:
我的申请因同样的原因被拒绝。我在应用程序升级时添加了家长网关,但我的应用程序中有广告,因此它再次被拒绝,因为点击广告离开应用程序并打开 itune 商店。我不确定是否有人可以在点击广告后和打开外部链接之前问父母问题。
我看到两个解决方案 1. 从应用程序中删除广告 2. 取消选择 Made for Kids
这是否意味着我们不能为儿童制作的应用程序投放广告?
我最近刚刚与 Apple 讨论过这个问题。
首先,他们将把它留给开发人员来实现,而不必告诉我们他们将接受什么。但是,我确实设法从 Apple 那里得知,它实际上也取决于您所针对的年龄组。如果你要去一个年龄较大的群体,父母的门一定更难克服。
一个简单的弹出窗口告诉用户只有在那之后它才是成年人是行不通的。必须有其他东西阻止用户。多点触控滑动、数学问题和历史问题被认为是可以接受的。
我担心的是,我认识很多父母,他们无法进行我见过的一些(45+62 等)中使用的简单算术运算。历史问题会很困难,因为我国的历史与你们的不同(班诺克本战役是什么时候?)。我见过的解决这个问题的一种方法是给出多项选择答案,但是如果有三个选项,那么有 33% 的可能性猜测就足够了!多点触控滑动太容易了。
理想情况下,这确实应该由 Apple 作为需要密码的 iOS 的一部分来涵盖。至少它将标准化父母门。
根据第二行选项和不同问题的要求,我选择了四个选项之一,从而设置了父母门。我在这里的目标是让测验对父母来说足够容易,但同时随机猜测不太可能解决难题。四个选项是 25% 的机会是正确的,第二个问题降低到 6%。我认为这将适用于我的目标在要求的较年轻端。
** 我的父母门版本被接受。从第一个视图控制器我会调用父母门。如果失败,它将关闭并创建一个 UIAlertView 说明它失败。如果它通过了,那么它也会关闭并在完成时发送成功通知。调用视图控制器接收通知,然后执行如果它不必做父母门会做的任何事情!
鉴于这似乎仍然存在很多不确定性,我想我会分享我自己的经验。
因为我为年幼的孩子(六岁或类似的孩子)制作应用程序,所以我可以假设父母之门不需要太难。目前我实现了一个简单的 UIAlertView 来询问一个数学问题。由于其他答案之一中的评论,我实际上正在使这个问题变得更简单一些。
我正在做的是取两个 10 到 30 之间的随机数,并要求用户添加它们并输入答案。不幸的是,因为我现在在 UIAlertView 中执行此操作并且我需要一个编辑字段,这将 iOS 使用的标准提高到了 5.0。查看我的应用程序的 Flurry 数据,在过去的一个月里,iOS 5 下的任何内容几乎没有注册(不到总数的 1%),所以我不太担心。
我仍在考虑是否不能在我们所学的数学知识的基础上让成人变得更简单,但不一定对孩子来说更简单。例如,确保要添加的任何数字都是偶数,这可能会使许多人更容易。与五的倍数一起工作会更容易,而我认为孩子们根本没有学会这些技巧,所以对他们来说不会有太大的不同。
我在 App Store 中有三个不同的应用程序使用相同的方法并且它们都被接受了,即使它们得到了不同的人的审查(我可以看出他们在其他方面的决定有多么愚蠢)所以我假设这种方法是批准。我还没有做的是试图想出一种方法来判断用户是否觉得这很烦人,或者大多数人是否可以不用太担心来处理这个问题。
你可能想试试这个 cocoapod 库: https ://cocoapods.org/pods/HYParentalGate
我用 swiftUI 为需要它的人创建了一个。
它会生成 3 个随机数,然后要求您按该顺序按下数字按钮,如果正确,它会隐藏不透明的门,所以我在加载时需要门的屏幕上使用它,所以当门隐藏时,它会显示另一个查看下方。如果按下的数字不正确,它会关闭门并将视图关闭并返回原始视图。
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()
}
}
}
}
}
这是我今天做的一个。我还没有得到苹果的回复。它已通过应用审核
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)
}
}