AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Fast, modern and beafutiful way to promote your apps
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
MoPromoteKit is a powerful and easy-to-use Swift Package that helps iOS developers cross-promote their other apps. It fetches all apps from the same developer using the iTunes Search API and displays them with beautiful SwiftUI cards, featuring global ratings aggregation from 80+ countries.檢視完整 README ↗MoPromoteKit is a powerful and easy-to-use Swift Package that helps iOS developers cross-promote their other apps. It fetches all apps from the same developer using the iTunes Search API and displays them with beautiful SwiftUI cards, featuring global ratings aggregation from 80+ countries.
https://github.com/mkhasson97/MoPromoteKit.gitdependencies: [
.package(url: "https://github.com/mkhasson97/MoPromoteKit", from: "1.0.0")
]
The simplest way to use MoPromoteKit — just pass your app's Bundle ID:
import SwiftUI
import MoPromoteKit
struct SettingsView: View {
var body: some View {
ScrollView {
VStack(spacing: 16) {
Text("Settings")
.font(.largeTitle)
.fontWeight(.bold)
// Using Bundle ID (recommended)
MoPromoteKit.developerAppsView(
currentBundleId: "com.yourcompany.yourapp"
)
}
}
}
}
MoPromoteKit can automatically detect your app's bundle ID:
struct SettingsView: View {
var body: some View {
ScrollView {
// Auto-detects the current app's Bundle ID!
MoPromoteKit.developerAppsView()
}
}
}
You can also use the numeric App Store ID:
struct SettingsView: View {
var body: some View {
ScrollView {
MoPromoteKit.developerAppsView(currentAppId: 1234567890)
}
}
}
Configure MoPromoteKit globally in your App file:
import SwiftUI
import MoPromoteKit
@main
struct MyApp: App {
init() {
// Configure MoPromoteKit
MoPromoteKit.configure { config in
config.maxApps = 6
config.cardStyle = .regular
config.showTitle = true
config.countryCode = "us" // Optional: force specific country
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Perfect for adding a "More Apps" section to your settings:
struct SettingsView: View {
var body: some View {
List {
Section("General") {
// Your settings
}
Section {
// Using Bundle ID
MoPromoteKit.developerAppsView(
currentBundleId: "com.yourcompany.yourapp"
)
// Or using App Store ID
// MoPromoteKit.developerAppsView(currentAppId: 1234567890)
} header: {
Text("More Apps")
}
}
}
}
Promote specific apps by their Bundle IDs or App Store IDs:
struct FeaturedAppsView: View {
var body: some View {
ScrollView {
// Using Bundle IDs
MoPromoteKit.manualAppsView(bundleIds: [
"com.yourcompany.app1",
"com.yourcompany.app2",
"com.yourcompany.app3"
])
// Or using App Store IDs
// MoPromoteKit.manualAppsView(appIds: [1234567890, 9876543210])
}
}
}
Combine featured apps with automatic developer discovery:
struct RecommendedAppsView: View {
var body: some View {
ScrollView {
// Using Bundle IDs
MoPromoteKit.hybridAppsView(
featuredBundleIds: ["com.yourcompany.app1", "com.yourcompany.app2"],
currentBundleId: "com.yourcompany.currentapp",
maxAdditional: 3
)
// Or using App Store IDs
// MoPromoteKit.hybridAppsView(
// featuredAppIds: [1234567890, 9876543210],
// currentAppId: 5555555555,
// maxAdditional: 3
// )
}
}
}
Add developer profile images to enhance branding:
struct SettingsView: View {
var body: some View {
ScrollView {
// With URL profile image
DeveloperAppsView.forSettings(
currentAppId: 1234567890,
developerProfile: .url("https://yoursite.com/developer-avatar.jpg")
)
// Or with local asset
DeveloperAppsView.forSettings(
currentAppId: 1234567890,
developerProfile: .asset("developer_avatar")
)
}
}
}
Use the compact style for sidebars or smaller sections:
struct SidebarView: View {
var body: some View {
VStack {
// Main content
MoPromoteKit.compactDeveloperAppsView(
currentAppId: 1234567890,
maxApps: 3
)
}
}
}
For dedicated "More Apps" screens:
struct MoreAppsView: View {
var body: some View {
NavigationView {
ScrollView {
MoPromoteKit.fullScreenDeveloperAppsView(currentAppId: 1234567890)
.padding()
}
.navigationTitle("More Apps")
.navigationBarTitleDisplayMode(.large)
}
}
}
Exclude specific apps and customize sorting:
struct CustomAppsView: View {
var body: some View {
ScrollView {
DeveloperAppsView(
currentAppId: 1234567890,
excludeAppIds: [9999999999], // Exclude competitor or deprecated apps
maxApps: 8,
cardStyle: .featured,
sortingOrder: .rating, // Sort by highest rated
showAnalytics: true, // Show analytics cards
developerProfile: .url("https://yoursite.com/avatar.jpg", size: 50)
)
}
}
}
Access the data programmatically for custom implementations:
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
// Fetch specific apps
let specificApps = try await MoPromoteKit.fetchApps(appIds: [
1234567890, 9876543210, 5555555555
])
// Fetch all developer apps with exclusions
let developerApps = try await MoPromoteKit.fetchDeveloperApps(
currentAppId: 1234567890,
excludeAppIds: [9999999999],
includeCurrentApp: false
)
// Get promotion insights
let insights = await MoPromoteKit.getPromotionInsights(appIds: [
1234567890, 9876543210, 5555555555
])
print("Total download potential: \(insights.totalDownloadPotential)")
print("Average rating: \(insights.averageRating)")
print("Top performing app: \(insights.topPerformingApp?.trackName ?? "None")")
print("Recommended order: \(insights.recommendedPromotionOrder)")
} catch {
print("Error: \(error)")
}
}
}
}
public struct Configuration {
/// Maximum number of apps to display (default: 10)
public var maxApps: Int = 10
/// Country code for App Store region (default: auto-detected)
public var countryCode: String?
/// Whether to show the "More Apps" title (default: true)
public var showTitle: Bool = true
/// Card display style (default: .regular)
public var cardStyle: CardStyle = .regular
/// Enable global ratings aggregation (default: true)
public var enableGlobalRatings: Bool = true
/// Cache duration for search results in seconds (default: 300)
public var cacheDuration: TimeInterval = 300
/// App selection mode (default: .allFromDeveloper)
public var appSelectionMode: AppSelectionMode = .allFromDeveloper(currentAppId: 0)
/// Sorting order for apps (default: .alphabetical)
public var sortingOrder: SortingOrder = .alphabetical
/// Custom title override
public var customTitle: String?
}
public enum CardStyle {
case regular // Standard detailed cards
case compact // Smaller cards for tight spaces
case featured // Large prominent cards with descriptions
}
public enum SortingOrder {
case alphabetical // Sort by app name A-Z
case rating // Sort by highest rating first
case releaseDate // Sort by newest first
case downloads // Sort by most reviews/downloads
case random // Random shuffle
case custom([Int]) // Custom order by app IDs
}
public enum AppSelectionMode {
case allFromDeveloper(currentAppId: Int)
case manual(appIds: [Int])
case hybrid(featuredAppIds: [Int], currentAppId: Int, maxAdditional: Int)
}
// Manual app promotion
MoPromoteKit.configureForManualPromotion(
appIds: [1234567890, 9876543210],
title: "Our Best Apps",
cardStyle: .featured
)
// Hybrid promotion
MoPromoteKit.configureForHybridPromotion(
featuredAppIds: [1234567890, 9876543210],
currentAppId: 5555555555,
maxAdditional: 3
)
// Predefined configurations
MoPromoteKit.configure(.forSettings) // For settings pages
MoPromoteKit.configure(.compact) // For compact displays
MoPromoteKit.configure(.fullScreen) // For full-screen displays
MoPromoteKit's standout feature is global ratings aggregation. Instead of showing ratings from just one country, it:
You can debug the global ratings feature:
Task {
let debug = await MoPromoteKit.debugGlobalRatings(appId: 1234567890)
print(debug)
}
Output example:
🌍 Global Ratings Analysis for App ID: 1234567890
==================================================
📊 Summary:
• Total Reviews: 45,234
• Weighted Average: 4.3⭐
• Markets with data: 28/30
🌟 Top Markets:
1. 4.5⭐ (12,543 reviews)
2. 4.4⭐ (8,921 reviews)
3. 4.2⭐ (6,432 reviews)
...
Add professional developer branding with profile images:
DeveloperAppsView.forSettings(
currentAppId: 1234567890,
developerProfile: .url("https://yoursite.com/developer-avatar.jpg")
)
DeveloperAppsView.forSettings(
currentAppId: 1234567890,
developerProfile: .asset("developer_avatar") // Image in your app bundle
)
DeveloperAppsView.forSettings(
currentAppId: 1234567890,
developerProfile: .url("https://yoursite.com/avatar.jpg", size: 60)
)
Get detailed insights about your app promotion performance:
let insights = await MoPromoteKit.getPromotionInsights(appIds: [
1234567890, 9876543210, 5555555555
])
// Access insights data
print("Total reviews across all apps: \(insights.totalDownloadPotential)")
print("Combined average rating: \(insights.averageRating)")
print("Best performing app: \(insights.topPerformingApp?.trackName ?? "None")")
print("Categories represented: \(insights.categoryBreakdown)")
print("Recommended promotion order: \(insights.recommendedPromotionOrder)")
You can customize the appearance by modifying the configuration:
MoPromoteKit.configure { config in
config.cardStyle = .featured
config.maxApps = 5
config.showTitle = false
config.sortingOrder = .rating
}
Use the convenience modifier for quick integration:
struct MyView: View {
var body: some View {
VStack {
Text("Welcome")
}
// Using Bundle ID
.withDeveloperApps(currentBundleId: "com.yourcompany.yourapp")
// Or zero-config
// .withDeveloperApps()
// Or App Store ID
// .withDeveloperApps(currentAppId: 1234567890)
}
}
When users tap "GET" on an app card, the App Store product page is shown inside your app as a sheet—powered by StoreKit's SKStoreProductViewController. Users can download the promoted app without ever leaving your app.
This behavior is automatic—no configuration needed.
MoPromoteKit is localized in 6 languages out of the box. The UI automatically adapts to the user's device language:
| Language | Code |
|---|---|
| 🇬🇧 English | en |
| 🇩🇪 German | de |
| 🇸🇦 Arabic | ar |
| 🇪🇸 Spanish | es |
| 🇫🇷 French | fr |
| 🇹🇷 Turkish | tr |
All UI strings (loading states, error messages, section titles, button labels) are automatically localized—no configuration needed.
MoPromoteKit supports 80+ App Store regions including:
Major Markets: US, UK, Canada, Australia, Germany, France, Italy, Spain, Netherlands, Sweden, Norway, Denmark, Finland, Japan, South Korea, China, Hong Kong, Taiwan, Singapore, India, Brazil, Mexico...
Complete list available via:
let countries = MoPromoteKit.supportedCountries
let majorMarkets = MoPromoteKit.majorMarkets
com.yourcompany.yourapp)Or use it directly in code: Bundle.main.bundleIdentifier
If you prefer to use the numeric App Store ID:
Or extract it from your App Store URL:
https://apps.apple.com/app/id1234567890
↑
This is your App ID
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
MoPromoteKit is available under the MIT license. See the LICENSE file for more info.
MIT License
Copyright (c) 2025 Mohammad Alhasson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Mohammad Alhasson
If you're using MoPromoteKit in your project, I'd love to hear about it! Feel free to:
Made with ❤️ in Swift
Made with ❤️ for the iOS developer community