I'm investigating the same questions.
As far as I remember there used to be a guideline in Design 4.4 Extensions which prohibited In-App-Purchases inside app extensions but I can't find it anymore, so apparently they've removed it. I think I have come across an app which sells IAPs inside its AUv3 extension so it seems to be fine. But please don't take my word for it.
I have implemented IAPs directly inside my framework, which is nested inside the extension and it works on my device. I am not sharing data with UserDefaults or anything like that. When I verify the receipt I make sure that I access the bundle and version identifier of the main app, because otherwise it will use the bundle identifier of the extension or framework which will not work.
I haven't had the chance to test it with a real release from the App Store yet and I came across this thread which is quite old but it made me realize that there could be a problem: Eventually the extension will not have access to the receipt in the Main Bundle when published on the App Store.
Please let me know in case you've figured out a way.
Post
Replies
Boosts
Views
Activity
My Objective-C function deallocateRenderResources() gets called.
My deinit{} function in Swift does not.
Have you figured out a solution in the meantime?
thanks for sharing. I don't know how to apply that in Objective-C world but it looks interesting.It turned out that in my case deinit() wasn't called because of retain cycles in Swift, which were actually quite easy to fix.
I used to have access to financial reports but now there are zero. I don't know what's going on.
As far as I understand you can just split the string into three parts and then base64 decode each part. The second part should give you all the necessary information about the transaction ( structure should be similar to JWSTransactionDecodedPayload: https://developer.apple.com/documentation/appstoreserverapi/jwstransactiondecodedpayload )
$array = explode(".", $json_decoded["signedTransactionInfo"]);
return json_decode(base64_decode( $array[1] ), true);
Update: While splitting the string into three parts and encoding the second part might be enough for processing calls like transactions or history, it is not recommended doing so, especially not when decoding App Store Server Notifications, since it is not safe. Try using a library like this instead:
https://github.com/readdle/app-store-server-api
The error message disappears when you retreive the super.fullState data first and then add your dictionary to that one, see code below:
override var fullState: [String: Any]? {
get {
// save preset
var state = super.fullState ?? [:]
state["fullStateParams"] = [:] // your dictionary here
return state
}
set {
// load preset
if let state:[String:Any] = newValue{
if let stateFullParams:[String:[String:Any]] = state["fullStateParams"] as? [String:[String:Any]]{
// do something with your dictionary
}
}
}
}
Unfortunately this solution still doesn't solve the problem on how to save the preset inside the plugin.
Have you found a solution in the meantime?
Ok I think saving a preset inside the plugin goes something like this:
In order for the preset to be saved inside your AUv3 app container you'll need to override the currentPreset property in which the selected preset gets passed to the fullStateForDocument property, see code below:
override var supportsUserPresets: Bool{ get{ return true } }
private var _currentPreset: AUAudioUnitPreset?
override var currentPreset: AUAudioUnitPreset? {
get { return _currentPreset }
set {
// If the newValue is nil, return.
guard let preset = newValue else {
_currentPreset = nil
return
}
// Factory presets need to always have a number >= 0.
if preset.number >= 0 {
_currentPreset = preset
// User presets are always negative.
}else {
// Attempt to restore the archived state for this user preset.
do {
fullStateForDocument = try presetState(for: preset)
// Set the currentPreset after successfully restoring the state.
_currentPreset = preset
} catch {
print("Unable to restore set for preset \(preset.name)")
}
}
}
}
override var fullState: [String: Any]? {
get {
// save preset
var state = super.fullState ?? [:]
state["fullStateParams"] = [:] // your dictionary here
return state
}
set {
// load preset
if let state:[String:Any] = newValue{
if let stateFullParams:[String:[String:Any]] = state["fullStateParams"] as? [String:[String:Any]]{
loadPreset(array: stateFullParams) // do something with your dictionary
}
}
}
}
More information can be found here:
https://developer.apple.com/videos/play/wwdc2019/509/
https://developer.apple.com/documentation/audiotoolbox/audio_unit_v3_plug-ins/incorporating_audio_effects_and_instruments
https://developer.apple.com/documentation/audiotoolbox/audio_unit_v3_plug-ins/creating_custom_audio_effects