Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - TwoRingSoft/Pippin: Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift. · GitHub
Skip to content

Repository files navigation

Pippin

Swift 5.1platformsLicense

Pippin is a collection of tools to scaffold iOS app infrastructure and assist in development tasks like writing code, testing and debugging.

Getting started with a default setup is as easy as declaring a Podfile dependency:

pod'Pippin'

and, at some point during your app launch sequence:

import Pippin
import PippinAdapters
letenvironment=Environment.default(
bugReportRecipients:["andrew@tworingsoft.com"],
touchVizRootVC:UIViewController(nibName:nil, bundle:nil) // optional
)
// Crashlytics is a special situation
environment.crashReporter =CrashlyticsAdapter(debug:true)
// other optional peripherals
environment.locator =CoreLocationAdapter(locatorDelegate:self)
environment.connectEnvironment()

You've just gotten the following, with minimal boilerplate:

  • logging
  • crash reporting
  • bug reporting
  • progress indicators
  • alert dialogs
  • fonts
  • app and launch information
  • data model
  • touch visualization
  • launch arguments and environment variables
  • an authorized CLLocationManager (an authorized AVCaptureDevice may be obtained similarly)

Podspecs

There are five podspecs to deliver these tools, see each's README for more information:

Note: there are several reasons these are delivered via separate podspecs instead of one podspec with multiple podspecs. Those two spec levels are not equivalent for all functionalities.

  • Issues with installing test_specs for just one subspec.
  • Not supported to install a subspec using Pod:configurations: CocoaPods/CocoaPods#3503.

The old Pippin.podspec is now an umbrella framework that pulls in PippinCore, PippinAdapters, PippinLibrary and PippinTesting for convenience.

Example projects

These are used for testing and can be evaluated using pod try:

Releasing

make patch # Bump VERSION patch (run before first deploy-beta in a cycle)
make minor # Bump VERSION minor
make major # Bump VERSION major
make deploy-beta # Tag an RC from [Unreleased], push, create GitHub prerelease
make deploy # Consolidate RC entries, tag, push, create GitHub release

Version bumping and deploying are separate steps:

make minor # 1.2.3 → 1.3.0
make deploy-beta # tags 1.3.0-RC1
make deploy-beta # tags 1.3.0-RC2 (no re-bump needed)
make deploy # consolidates all RC sections into 1.3.0

To change the target version mid-cycle, bump again before the next RC:

make minor # 1.2.3 → 1.3.0
make deploy-beta # 1.3.0-RC1
make major # 1.3.0 → 2.0.0
make deploy-beta # 2.0.0-RC2
make deploy # consolidates all RC sections into 2.0.0

Components

InfoPresenter (PippinAdapters-InfoViewController)

Presents an about sheet in a floating UIWindow so it works correctly from SwiftUI roots. Initialize once and call show() / dismiss().

letpresenter=InfoPresenter(
environment: environment,
acknowledgements:AppAcknowledgements(
specialThanks:"Some Library by Some Author",
disclaimer:"For informational purposes only.",
environment: environment
),
contactEmails:["support@example.com"],
companyLink:MyCompanyLink())
presenter.show()

AppAcknowledgements accepts:

ParameterDescription
specialThanksFree-form text rendered under a "Special thanks" heading
disclaimerFree-form text rendered under a "Disclaimer" heading
acknowledgementsPlistURLURL to a CocoaPods-style acknowledgements plist for library licenses

CloudKitCoreDataController (PippinAdapters-CloudKitCoreData)

Wraps an NSPersistentCloudKitContainer with a private + shared store for CloudKit sync and sharing, automatic lightweight migration, and remote-change observation.

It can also push the Core Data model's CloudKit schema to the Development environment at launch via initializeCloudKitSchema. Because programmatic schema initialization is only permitted against Development (it fails against Production), the caller chooses a CloudKitSchemaInitializationPolicy:

PolicyBehaviorUse for
.neverDon't initialize the schema.Production/Release builds (promote the schema via the CloudKit Dashboard instead).
.onModelVersionChangeInitialize once per model version. The controller derives the version from managedObjectModel.versionIdentifiers, records the last successfully-initialized version in UserDefaults (keyed by modelName), and re-runs only when it changes.Debug and staging builds, so new entities/fields auto-deploy to Development on first launch.
.alwaysInitialize on every launch, regardless of the recorded version.A manual override, e.g. after resetting the Development environment.
letcontroller=CloudKitCoreDataController(
modelName:"MyApp",
cloudKitContainerIdentifier:"iCloud.com.example.myapp",
managedObjectModel: model,
inMemory:false,
schemaInitialization:.onModelVersionChange,
resetSharedStore:false)

The version marker is written only on success, so a failed attempt (offline, etc.) retries on the next launch; inspect controller.schemaInitializationError for the most recent failure.

Contribute

Issues and pull requests are welcome!

Testing

rake test

Runs a collection of Rake tasks which themselves may be run independently:

  • example_smoke_tests
  • unit_tests
  • test_smoke_test
  • subspec_smoke_test

example_smoke_tests

For each project in Examples/ try to pod install and build.

unit_tests

Run the unit test suites created for any test_specs of any Pippin podspecs.

test_smoke_test

pod install and try to build the Example/Pippin.xcodeproject unit and UI test targets, which both declare dependencies on PippinLibrary and PippinTesting.

subspec_smoke_test

An integration smoke test, which generates an Xcode project for each subspec of each Pippin podspec, each in both Swift and Objective-C, to try building after pod installing that subspec. Each project is deposited under PippinTests/SmokeTests.

PippinTests/ also contains the template project source code in ObjcApp/ and SwiftApp/, plus the template Podfile.

Podspec test_specs

Pippin podspecs currently with unit tests located under Tests/:

  • PippinLibrary
  • PippinTesting

TODO

  • A changelog presenter for when an app is updated, showing the new changelog entries since the last version that had run
  • macOS support
  • add "other apps" links to infovc
  • swap out icons8 icons for SFSymbols

Thanks!

If this project helped you, please consider leaving a tip 🤗

About

Utilities to scaffold iOS apps and simplify working with Cocoa/UIKit/XCTest API in Swift.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages