What models and fields do I need to handle subscriptions such as Apple's Autorenewable Subscriptions? - django

I want to build an autorenewable subscription service, with an introductory trial period. There doesn't seem to be much written documentation on what models and fields I need to best model (and futureproof) my subscriptions. I'm starting with Apple's App store right now, but I do have a web interface and want to go to the Play Store at some point.
From this video: https://developer.apple.com/videos/play/wwdc2018/705/ it seems like the minimum I need is something like a Subscription model with fields userId, productId, originalTransactionId, latestExpiresDate, consumedProductDiscounts, latestReceiptData.
Is there anything else I need?
Will I be able to properly retrieve other subscription information in the future and augment my table (i.e. the billingRetry information as suggested in the video for grace periods; my understanding is by sending the saved receipt data I can get the JSON blob again and retrieve additional fields if I need to)?
Is this extensible to co-exist with web and Play Store subscriptions?

These is the models we use to handle the subscription. maybe it helps you.
struct BillingTransaction : Codable {
var expires_date: String
var original_purchase_date: String
var is_in_intro_offer_period: Bool
var product_id: String
var original_transaction_id: Int
var transaction_id: Int
}
struct BillingReceipt : Codable {
var app_item_id: String
var application_version: String
var bundle_id: String
var in_app: [BillingTransaction]
}
struct BillingRenewalInfo : Codable {
var product_id: String
var auto_renew_product_id: String
var auto_renew_status: Int
var is_in_billing_retry_period: Int
var original_transaction_id: Int
}

Related

Creating Repository pattern for use with local .SQLite db in Swift

I am building a SwiftUI app that pulls information from a local .SQLite database (using the SQLite.swift wrapper from https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md). I need to build a repository that sits between the View Service and the Database Manager. I am very new to repository pattern, and am struggling to find 1) documentation for using repository pattern in Swift 5, and 2) what exactly needs to be in the repository.
I found this example for using repository pattern in Swift, but it uses a web-based API for its code examples, and I can't find anything for use with a local db.
Code below is what I have in the repository so far:
struct doMaster: Codable {
let doID: Int64
let doName: String
let doState: Bool
let doCompletedState: Bool
let doCategory: String
}
struct doDescription: Codable {
let doID: Int64
let doDescription: String
}
struct doStreaks: Codable {
let doID: Int64
let doStreak: Int64
}
struct doCategories: Codable {
let category: String
let categoryColor: String
}
class LocalRepository {
let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? ""
let task =
}
Any help would be very much appreciated. Thank you in advance!

Pass big data like images to widget? [duplicate]

#main
struct ClockWidgetExt: Widget {
private let kind: String = "ClockWidgetExt"
public var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider(), placeholder: PlaceholderView()) { entry in
HomeTestView()
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
}
}
How can I get data from my Main App to the widget?
You can add the AppGroup capability for both your Widget and App (here is a very good explanation how to add it).
UserDefaults
Instead of
UserDefaults.standard
just use the shared UserDefaults for your AppGroup:
UserDefaults(suiteName: <your_app_group>)
Then you can read/write data like explained in this answer.
File Container
With the AppGroup entitlement you get access to the shared File Container:
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <your_app_group>)!
and access an url like this:
let someFileURL = containerURL.appendingPathComponent("SomeFile.txt")
Then you can use your shared File Container like explained in this answer:
How to read files created by the app by iOS WidgetKit?
CoreData
You can create a shared CoreData container as well:
let storeURL = containerURL.appendingPathComponent("DataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)
let container = NSPersistentContainer(name: "DataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }
Then you can use your shared CoreData Container like explained in this answer:
Fetch data from CoreData for iOS 14 widget
Here is a GitHub repository with different Widget examples including the App Group Widget.
One simple way to do this is by adding both the app and the widget to the same App Group, and then storing and retrieving data from UserDefaults storage located in that App Group's container instead of the default UserDefaults storage for the app.
You can access this shared storage for your App Group by initializing UserDefaults using
UserDefaults(suiteName: "YOUR_APP_GROUP_NAME")
instead of accessing it using
UserDefaults.standard.
This article gives a more thorough description of the details of this process.

What is the best way to demux a publisher's Output?

I have an ObservableObject with a few publishers:
private class ViewModel: ObservableObject {
#Published var top3: [SearchResult] = []
#Published var albums: [SearchResult.Album] = []
#Published var artists: [SearchResult.Artist] = []
}
The endpoint is a URLSessionDataPublisher that sends a single collection of values that can be either an album or an artist (there are actually more types but I'm reducing the problem set here.) What is the best way in Combine to separate this collection out into 3 collections: [Album], [Artist], and an array of 3 results that can be either Artist or Album?
DatabaseRequest.Search(for: searchTerm)
.publisher()
// now i want to separate the collection out into [Album] and [Artist] and assign to my 3 #Published vars
.receive(on: DispatchQueue.main)
.sink { }
.store(in: bag)
You are hitting a bit of a (common) fallacy that Combine is responsible for passing the changed data in SwiftUI. It isn't. The only thing Combine is doing here is providing the content-less message that some data has changed, and then the SwiftUI components that are using the relevant model object go and look for their data.
The data transfer in SwiftUI is entirely using Binding, which are essentially get and set closures under the covers.
So you don't really need to worry about demuxing a combine stream - and there isn't one that has "one" of these kinds of data in it. Combine would have trouble with that since it's strongly typed for both Output type and Failure type.
There's a bit more written about this in Using Combine under the chapter
SwiftUI and Combine (chapter link to the free HTML version)

IBM Watson Alchemy news iOS SDK Swift

The IBM Watson iOS SDK using the Alchemy News service on Bluemix returns a string result which requires parsing to pull out the fields like url and cleaned title. ref: https://github.com/watson-developer-cloud/swift-sdk
I pull the string into an array and parse it in swift3 using some string methods but this is pretty ordinary and can produce unpredictable results
Is there a more elegant approach where I can access specific fields, like the url and cleaned title which I am passing to a UITableViewCell to select and segue to the url link.
sample code:
let alchemyDataNews = AlchemyDataNews(apiKey: apiKey)
let failure = { (error: Error) in print(error) }
let start = "now-14d" // 7 day ago
let end = "now" // today
let query = ["count": "15",
"dedup": "true",
"q.enriched.url.title": "[IBM]",
"return": "enriched.url.url,enriched.url.title" "enriched.url.title,enriched.url.entities.entity.text,enriched.url.entities.entity.type"]
Also I have noticed the search string [IBM] has a prefix of 0, i.e. 0[IBM] and have also seen an "A". What do these prefixes mean and where are they documented
Here is one way you can access the fields from a returned payload.
alchemyDataNews.getNews(from: "now-4d", to: "now", query: queryDict, failure: failWithError) { news in
for doc in (news.result?.docs)! {
var cleanedTitle = doc.source?.enriched?.url?.cleanedTitle
var author = doc.source?.enriched?.url?.author
var title = doc.source?.enriched?.url?.title
}}
Also, here is a nice API reference link for alchemy data which contains all of the request parameters and filters.
https://www.ibm.com/watson/developercloud/alchemydata-news/api/v1/

Handling geocoding in Firebase?

Has anyone tried storing and/or searching on geocodes (e.g. lat/long) in Firebase? This is functionality that is built into MongoDB and as I'm considering using Firebase for our backend instead, I need to know how I'd handle this scenario in Firebase.
Thanks!
The folks at Firebase recently open-sourced a library that allows you to store and query location data in Firebase. In short, this is very easily accomplished because all keys in Firebase are strings, and Firebase has support for startAt() and endAt() queries that allow you to do the appropriate windowing for geohashes and bounding boxes.
For implementation details and usage, check out the live demos, source code, and their blog post on GeoFire.
Hey I just finished building a real time google map using firebase and GeoFire. GeoFire is really cool and easy to use. It allows you to query using lon lat and radius. It returns a key that you can use to query your firebase db. You set the key, while you create the geoFire object, to be whatever you want. It is usually a ref that you can use to get the object that is associated with that distance.
Here is a link to geoFire:
https://github.com/firebase/geofire-js
Here is an example use case:
You have a lon lat, that you got using navigator:
var lon = '123.1232';
var lat = '-123.756';
var user = {
name: 'test user',
longitude: lon,
latitude: lat
}
usersRef.push(user).then(function(response) {
var key = response.key;
var coords = [lon, lat];
geoFire.set(key, coords, function(success){
console.log('User and geofire object has been created');
});
})
Now you can query for the user using:
// Set your current lon lat and radius
var geoQuery = geoFire.query({
center: [latitude, longitude],
radius: radiusKm
});
geoQuery.on('key_entered', function(key, location, distance) {
// You can now get the user using the key
var user = firebaseRefUrl + '/' + key;
// Here you can create an array of users that you can bind to a scope in the controller
});
If you are using google maps. I reccomend you use angular-google-maps.
Its a really cool google maps directive that takes in an array of markers and circles. So when ever $scope.markers or $scope.circles change in the controller it will automatically be applied to the map without any messy code. They have very good documentation.
Here is a link:
http://angular-ui.github.io/angular-google-maps/