mirror of
https://github.com/MobAI-App/simslim.git
synced 2026-09-28 17:12:59 +02:00
--except store kept the AMS daemons (#22) but the purchase still failed with AMSErrorDomain code=10: the payment authorization sheet is hosted by Wallet (passd), which in turn requires the Finance datastore (financed), and both live in the 'other' category. Add them to the store category as shared labels and to the storekit doctor feature. Verified on an iPhone 16 / iOS 26.2 simulator with a StoreKit-config test app: stock passes; --except store on v0.6.0 reproduces issue #21; with passd alone the sheet still fails (passd cannot reach com.apple.financed.service.coredatastore); with passd+financed the payment sheet renders and the purchase flow proceeds.
95 lines
4.2 KiB
Go
95 lines
4.2 KiB
Go
package simslim
|
|
|
|
import "fmt"
|
|
|
|
// Feature is a user-facing capability backed by specific launchd daemons.
|
|
// Every label must also live in a Category (enforced in features_test.go), so a
|
|
// feature only ever names daemons the tool could actually have turned off.
|
|
type Feature struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Labels []string `json:"labels"`
|
|
}
|
|
|
|
// Features maps commonly required capabilities to the daemons they need running.
|
|
var Features = []Feature{
|
|
{ID: "push", Name: "Push notifications", Labels: []string{"com.apple.apsd"}},
|
|
// In-app purchase needs the store daemons plus AMS, which runs the
|
|
// payment sheet task, plus Wallet (passd) which hosts the sheet UI and
|
|
// Finance (financed) which passd requires — products load without them
|
|
// but purchases fail at sheet presentation.
|
|
{ID: "storekit", Name: "StoreKit / in-app purchase", Labels: []string{
|
|
"com.apple.storekitd",
|
|
"com.apple.itunesstored",
|
|
"com.apple.amsaccountsd",
|
|
"com.apple.amsengagementd",
|
|
"com.apple.amsondevicestoraged",
|
|
"com.apple.passd",
|
|
"com.apple.financed",
|
|
}},
|
|
{ID: "app-store", Name: "App Store", Labels: []string{"com.apple.appstored", "com.apple.itunesstored"}},
|
|
{ID: "universal-links", Name: "Universal links / associated domains", Labels: []string{"com.apple.swcd"}},
|
|
{ID: "spotlight", Name: "Spotlight & Settings search", Labels: []string{"com.apple.searchd", "com.apple.searchtoold"}},
|
|
{ID: "siri", Name: "Siri & speech", Labels: []string{"com.apple.assistantd", "com.apple.corespeechd"}},
|
|
{ID: "icloud", Name: "iCloud sync", Labels: []string{"com.apple.cloudd"}},
|
|
{ID: "keychain-sync", Name: "iCloud Keychain", Labels: []string{"com.apple.akd"}},
|
|
{ID: "contacts", Name: "Contacts", Labels: []string{"com.apple.contactsd"}},
|
|
{ID: "calendar", Name: "Calendar", Labels: []string{"com.apple.calaccessd"}},
|
|
{ID: "reminders", Name: "Reminders", Labels: []string{"com.apple.remindd"}},
|
|
{ID: "mail", Name: "Mail", Labels: []string{"com.apple.email.maild"}},
|
|
{ID: "photos", Name: "Photos library & analysis", Labels: []string{"com.apple.assetsd", "com.apple.photoanalysisd"}},
|
|
{ID: "health", Name: "HealthKit", Labels: []string{"com.apple.healthd"}},
|
|
{ID: "homekit", Name: "HomeKit", Labels: []string{"com.apple.homed"}},
|
|
{ID: "imessage", Name: "iMessage & FaceTime", Labels: []string{"com.apple.identityservicesd"}},
|
|
{ID: "widgets", Name: "Widgets & Live Activities", Labels: []string{"com.apple.chronod", "com.apple.liveactivitiesd"}},
|
|
{ID: "wallet", Name: "Wallet & passes", Labels: []string{"com.apple.passd"}},
|
|
{ID: "maps", Name: "Maps background services", Labels: []string{"com.apple.Maps.mapssyncd"}},
|
|
{ID: "weather", Name: "Weather", Labels: []string{"com.apple.weatherd"}},
|
|
{ID: "news", Name: "News", Labels: []string{"com.apple.newsd"}},
|
|
{ID: "game-center", Name: "Game Center", Labels: []string{"com.apple.gamed"}},
|
|
{ID: "find-my", Name: "Find My", Labels: []string{"com.apple.findmy.findmylocated"}},
|
|
{ID: "screen-time", Name: "Screen Time", Labels: []string{"com.apple.ScreenTimeAgent"}},
|
|
}
|
|
|
|
func featureByID(id string) (Feature, bool) {
|
|
for _, f := range Features {
|
|
if f.ID == id {
|
|
return f, true
|
|
}
|
|
}
|
|
return Feature{}, false
|
|
}
|
|
|
|
// resolveFeatures maps requested IDs to their Features, erroring on the first
|
|
// unknown one so a typo in --requires fails loudly instead of passing silently.
|
|
func ResolveFeatures(ids []string) ([]Feature, error) {
|
|
out := make([]Feature, 0, len(ids))
|
|
for _, id := range ids {
|
|
f, ok := featureByID(id)
|
|
if !ok {
|
|
return nil, fmt.Errorf("unknown feature %q (see `simslim doctor --list`)", id)
|
|
}
|
|
out = append(out, f)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// diagnoseFeatures reports, for each feature, which of its daemons the device
|
|
// currently has disabled. A feature is OK only when none of them are.
|
|
func DiagnoseFeatures(features []Feature, disabled map[string]bool) DoctorOutput {
|
|
statuses := make([]FeatureStatus, 0, len(features))
|
|
allOK := true
|
|
for _, f := range features {
|
|
var down []string
|
|
for _, l := range f.Labels {
|
|
if disabled[l] {
|
|
down = append(down, l)
|
|
}
|
|
}
|
|
ok := len(down) == 0
|
|
allOK = allOK && ok
|
|
statuses = append(statuses, FeatureStatus{ID: f.ID, Name: f.Name, OK: ok, Disabled: down})
|
|
}
|
|
return DoctorOutput{OK: allOK, Features: statuses}
|
|
}
|