Hi, endecotp.
The receipt/sandboxReceipt I guess it's a bug that App Store should fix.
I tried the develop version of TPInAppReceipt, it does not work because when compute macos_guid, many code can't compiler when target is My Mac (Designed for iPad). But I have another project, that's designed for Mac, so it should be able to get it's guid data, since the guid data is unique per mac (i guess), so i can use the guid data returns by the mac project, to see if it can validates my iOS receipt? I'll give it a try.
You can follow our discuss in TPInAppReceipt here: https://github.com/tikhop/TPInAppReceipt/issues/73
Update: I try to get the macos_guid from another project that build for mac, and use that guid data to verify my iOS project runs on mac, and it fails because the computed hash is not equal to receipt hash. maybe the guid data is not the same for different projects?
Post
Replies
Boosts
Views
Activity
I tried SwiftStoreKit & TPInAppReceipt in running iOS app to M1 mac book, it does not work.
I try to run my app in mac, finish the purchase process, and rerun it to see if it passes local receipt validation. But in this situation, my receipt file name is 'sandboxReceipt', however, the path 'Bundle.main.appStoreReceiptURL' returns 'receipt', hence the appStoreReceiptData returns by SwiftStoreKit is nil.
so I download my app by app store, finish the purchase process. My app version of App Store using SwiftStoreKit & OpenSSL to validate receipt, i reopen the download app, the local receipt validation fails, which is expected.
now i got both the sandboxReceipt & receipt, so i run my app with Xcode in mac again. Now i got the receipt data, and enter the validation process in TPInAppReceipt, and the validation failed.
I notice in the 'guid' method, it actually runs the same block as in iOS device. I guess the expected result is to run the last block.
fileprivate func guid() -> Data
{
#if os(watchOS)
var uuidBytes = WKInterfaceDevice.current().identifierForVendor!.uuid
return Data(bytes: &uuidBytes, count: MemoryLayout.size(ofValue: uuidBytes))
#elseif !targetEnvironment(macCatalyst) && (os(iOS) || os(tvOS))
var uuidBytes = UIDevice.current.identifierForVendor!.uuid <---------------------- code runs here!
return Data(bytes: &uuidBytes, count: MemoryLayout.size(ofValue: uuidBytes))
#elseif targetEnvironment(macCatalyst) || os(macOS)
var masterPort = mach_port_t()
var kernResult: kern_return_t = IOMasterPort(mach_port_t(MACH_PORT_NULL), &masterPort)
...
#endif
}
Here is my debug information:
let device = UIDevice.current
log.info([
	"=== Device Information ===",
	"Name: \(device.name)",
	"System Name: \(device.systemName)",
	"System Version: \(device.systemVersion)",
	"Model: \(device.model)",
	"Localized Model: \(device.localizedModel)",
].joined(separator: "\n"))
/* output:
=== Device Information ===
Name: Alen’s MacBook Pro 13
System Name: iOS
System Version: 14.2
Model: iPad
Localized Model: iPad/
i just find that enter translate:// in safari will show the open in translate prompt, but will not actually open the app.
Just find this question here, that also answers my question: https://developer.apple.com/forums/thread/653863
A widget must either have an IntentConfiguration or a StaticConfiguration, so you can't do exactly what you're describing with just one widget. You can accomplish a similar effect by making two widgets that use the same implementation for their timeline provider and view methods, and provide both of them with a WidgetBundle.
I only see the answer after post this comment, so forget about this.
Using Xcode 12 beta 5, still having this issue: Widget works locally on a device from Xcode but not after I distribute it through TestFlight, it just disappeared. Any ideas?
Below is my codes:
struct Provider: IntentTimelineProvider {
typealias Entry = ScreenTimeEntry
typealias Intent = ConfigurationIntent
func placeholder(with: Context) -> ScreenTimeEntry {
let entry = ScreenTimeEntry.sample
return entry
}
public func snapshot(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (ScreenTimeEntry) -> ()) {
let entry = ScreenTimeEntry(date: Date(), configuration: configuration)
completion(entry)
}
public func timeline(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entries: [ScreenTimeEntry] = [
ScreenTimeEntry(date: currentDate, configuration: configuration)
]
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}