PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture.

Overview

PinpointKit Logo

BuddyBuild CocoaPods Compatible Carthage compatible

PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture.

Screenshots

Features

  • Shake to trigger feedback collection
  • Add arrows, boxes, and text to screenshots to point out problems.
  • Blur our sensitive information before sending screenshots
  • Automatic, opt-in system log collection (iOS 9.x only)
  • Customize everything
    • The color of the arrows, and boxes
    • The text in the interface
    • How and where your feedback is sent
  • Absolutely free and open source
  • No backend required

Requirements

  • iOS 9.0+
  • Xcode 12+
  • Swift 5.0

Note: ScreenshotDetector depends on the Photos framework to access the user’s photo library. This requires you to add an entry for the NSPhotoLibraryUsageDescription key in your Info.plist file describing your app’s use of the user’s photo library. As of iOS 10, failure to provide a value for this key could cause your submission to the App Store to be rejected by Apple, or cause your app to exit upon attempting to access the user’s photo library. ScreenshotDetector is excluded by default when installing via CocoaPods, but is included otherwise.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

CocoaPods 1.0.0+ is required to build PinpointKit.

To integrate PinpointKit into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '9.0'
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'PinpointKit', '~> 1.5.0'
end

Then, run the following command:

$ pod install

We also offer a convenience class, ScreenshotDetector that is available via the ScreenshotDetector subspec. This class provides delegate callbacks when the user takes a screenshot while using your app. Please see the Requirements section regarding inclusion of ScreenshotDetector. You can add this to your project by adding the following line in your Podfile, in addition to the one for PinpointKit above:

pod 'PinpointKit/ScreenshotDetector', '~> 1.5.0'

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate PinpointKit into your Xcode project using Carthage, specify it in your Cartfile:

1.5.0 ">
github "Lickability/PinpointKit" ~> 1.5.0
  • Run carthage update to build the framework.
  • Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the “Targets” heading in the sidebar.
  • In the tab bar at the top of that window, open the “General” panel.
  • Drag the built PinpointKit.framework from the Carthage build folder into the “Embedded Binaries” section.

Manually

If you prefer not to use either of the aforementioned dependency managers, you can integrate PinpointKit into your project manually.

Embedded Framework

  • Open up Terminal, cd into your top-level project directory, and run the following command if your project is not initialized as a git repository:
$ git init
  • Add PinpointKit as a git submodule by running the following command:
$ git submodule add -b master https://github.com/Lickability/PinpointKit.git
  • Open the new PinpointKit/PinpointKit folder, and drag the PinpointKit.xcodeproj into the Project Navigator of your application’s Xcode project.

    It should appear nested underneath your application’s blue project icon. Whether it is above or below all the other Xcode groups does not matter.

  • Select the PinpointKit.xcodeproj in the Project Navigator and verify the deployment target matches that of your application target.

  • Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the “Targets” heading in the sidebar.

  • In the tab bar at the top of that window, open the “General” panel.

  • Click on the + button under the “Frameworks, Libraries, and Embeeded Content” section.

  • You may see two different PinpointKit.xcodeproj folders each with two different versions of the PinpointKit.framework nested inside a Products folder.

  • Select the top PinpointKit.framework for iOS.

  • And that’s it!

The PinpointKit.framework is automatically added as a target dependency, linked framework and embedded framework in a “Copy Files” build phase which is all you need to build on the simulator and a device.

Usage

Once PinpointKit is installed, it’s simple to use.

Initialize an instance of PinpointKit, specifying an array of feedback recipients used to pre-populate email addresses to which feedback can be sent:

let pinpointKit = PinpointKit(feedbackRecipients: ["[email protected]"])

To display a feedback view controller, add the following code where you want the feedback to display, passing the view controller from which PinpointKit should present:

pinpointKit.show(from: viewController)

Note: Be sure to keep a strong reference to your instance of PinpointKit for the duration of its use.

If you want to have the feedback view display from a shake gesture, simply add the following to your application delegate, replacing ["[email protected]"] with your array of email recipients and AppDelegate with your application delegate’s name:

private static let pinpointKit = PinpointKit(feedbackRecipients: ["[email protected]"])
var window: UIWindow? = ShakeDetectingWindow(frame: UIScreen.main.bounds, delegate: AppDelegate.pinpointKit)

If you don’t want to use PinpointKit’s default configuration, you can specify both Configuration and PinpointKitDelegate instances on initialization of PinpointKit.

The Configuration struct allows you to specify how the feedback view looks and behaves, while the PinpointKitDelegate instance provides hooks into the state of the feedback being sent.

Customization

PinpointKit uses a protocol-oriented architecture which allows almost everything to be customized. Here are some examples of what’s possible:

  • Implement a JIRASender that conforms to Sender, allowing users to send feedback directly into your bug tracker.
  • Supply your own console log collector that aggregates messages from your third-party logging framework of choice by conforming to LogCollector
  • Change how logs are viewed by creating your own view controller conforming to LogViewer.

For more information on what you can customize, take a peek at the documentation of Configuration.

Apps Using PinpointKit

Here are just a few of the apps and companies using PinpointKit to collect feedback. If your app does too, submit a pull request!

License

PinpointKit is available under the MIT license. See the LICENSE file for more information.

About

Lickability Logo

PinpointKit is built and maintained by Lickability, a small software studio in New York that builds apps for clients and customers. If you or your team need help building or updating an app, say [email protected]. We’d love to hear more about your project.

Huge thanks to our other contributors, including Kenny Ackerson, Paul Rehkugler, and Caleb Davenport.

Comments
  • iOS 12, Xcode 10, and Swift 4.2 Updates

    iOS 12, Xcode 10, and Swift 4.2 Updates

    With the Xcode 10 GM available:

    • [x] Perform recommended updates from Xcode on the framework and sample project.
    • [x] Migrate to the latest Swift version.
    • [x] Ensure both the framework and sample projects compile without warning.
    • [x] Test all 3 install methods (CocoaPods, Carthage, and manual).
    • [x] Update the README for Xcode and Swift Requirements.
    • [x] Smoke test the sample project built with these updates on iOS 12 and earlier OS versions, creating follow-up bugs/issues for anything that behaves abnormally.
    opened by mliberatore 14
  • Makes AnnotationView a protocol

    Makes AnnotationView a protocol

    There didnt seem to be a great reason that this was an abstract base class, and leaves possibility for things to break without warning (or a new annotation to be implemented wrong, or based on some private behavior)

    This also lets use make the current annotations final

    WIP-ish, relatively rough, etc

    opened by Pearapps 10
  • Replace deprecated GLKView with MTKView

    Replace deprecated GLKView with MTKView

    Closes #268

    What It Does

    This PR replaces GLKView with MTKView to fix warnings related to GLKView:

    • 'GLKView' is deprecated: first deprecated in iOS 12.0 - OpenGLES API deprecated

    How to Test

    Add a blur annotation to your screenshot.

    Notes

    I added a workaround to resolve the issue of image flipping vertically when run in the simulator. See this article for reference.

    opened by woxtu 7
  • PinpointKit 1.0

    PinpointKit 1.0

    opened by irace 7
  • Easier Specification Of Email Recipients

    Easier Specification Of Email Recipients

    Closes #124

    The example given in #124 would be nice, but would require exposing PinpointKit’s configuration as a var would introduce shared mutable state on PinpointKit, which is avoided in much of the framework. Instead, I dropped defaultPinpointKit and added a convenience initializer to PinpointKit to keep things immutable:

    public convenience init(feedbackRecipients: [String], delegate: PinpointKitDelegate? = nil) {
        let configuration = Configuration(feedbackRecipients: feedbackRecipients)
    
        self.init(configuration: configuration, delegate: delegate)
    }
    

    I’m open to discussion on the pros and cons of both approaches. Now, instead of using PinpointKit.defaultPinpointKit, for use with ShakeDetectingWindow:

    class AppDelegate: UIResponder, UIApplicationDelegate {
        let pinpointKit = PinpointKit(feedbackRecipients: ["[email protected]"])
        lazy var window: UIWindow? = ShakeDetectingWindow(frame: UIScreen.mainScreen().bounds, delegate: self.pinpointKit)
    }
    

    Note since we no longer have defaultPinpointKit which lives forever, the caller must keep a reference to their configured PinpointKit. This is because the ShakeDetectingWindow’s delegate is weak (as it should be), and we’re using an instance of PinpointKit as the delegate.

    Similarly, without ShakeDetectingWindow, in our example project, we must keep a separate reference to our PinpointKit:

    final class ViewController: UITableViewController {
    
    +   let pinpointKit = PinpointKit(feedbackRecipients: ["[email protected]"])
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Hides the infinite cells footer.
            tableView.tableFooterView = UIView()
        }
    
        override func viewDidAppear(animated: Bool) {
            super.viewDidAppear(animated)
    
    -       PinpointKit.defaultPinpointKit.show(fromViewController: self)        
    +       pinpointKit.show(fromViewController: self)
        }
    }
    
    opened by mliberatore 6
  • Gesture Detecting UIWindow

    Gesture Detecting UIWindow

    What it is

    Creates a UIWindow subclass to detect a shake motion. See: #10.


    To Do

    • [ ] ~~Can probably use Many Controllers to avoid subclassing UIWindow in general, since -motionEnded:withEvent: is a UIResponder method. There’s nothing requiring this to be a UIWindow at all.~~ (not going to do this)
    • [x] Delegate back to PinpointKit to actually present.
    • [x] Add this to the example project.
    opened by paulrehkugler 6
  • Screenshot Detector

    Screenshot Detector

    Almost all of #15.

    Screenshot

    img_0846

    What it Does

    Implements a screenshot detector class.

    How to Test

    I tested this in a sample project (attached here).

    Notes

    Haven’t hooked this up yet to anything in PinpointKit.

    TestDetector.zip

    opened by mattbischoff 6
  • Initial Project File Setup

    Initial Project File Setup

    Resolves https://github.com/Lickability/PinpointKit/issues/7.


    This creates a project file to work in, with the directory structure and scheme sharing required to eventually support CocoaPods, Carthage, and the Swift Package Manager. It also creates an Asset Catalog, named PinpointKitMedia.xcassets to avoid conflicts with the default asset catalog name (Media.xcassets) in the “Quick Open...” Xcode menu when consuming this Framework.

    opened by paulrehkugler 6
  • Bar Button Item Customization

    Bar Button Item Customization

    What it Does

    • Adds the ability to customize bar buttons on EditImageViewController
    • Introduces a new Appearance property, editorDoneButtonFont, since the editorTextAnnotationDoneButtonFont was being used for more than just the text annotation dismiss button.
    • Renames editorTextAnnotationDoneButtonFont to editorTextAnnotationDismissButtonFont for better disambiguation.

    How to Test

    1. Run git revert -n 0db8fa2, which uses a custom implementation of EditImageViewControllerBarButtonItemProviding.
    2. View the test code in ViewController.swift, which makes the right bar button item log to the console, and the left bar button item dismiss.
    3. Make some modifications like setting allowsHidingBarButtonItemsWhileEditingTextAnnotations to true in this test implementation, and verify the results.
    opened by mliberatore 5
  • Allow Customizing Feedback

    Allow Customizing Feedback

    Closes #134 by allowing the customization of Feedback’s body and title.

    To test with a sample subclass, run git revert -n e9403c8 in Terminal and see the incorporation of MySender in ViewController.swift.

    This PR makes a few properties on Feedback public vars instead of lets. This allows for interception / copying / modifying of Feedback by subclassing MailSender as seen in 93b9f71. I’d like to open the discussion on alternatives though, as I don’t think making the developer subclass is necessarily the most ideal solution to specifying an email subject and body.

    Pros

    • Simple for developer to implement.
    • Allows for up-to-the-moment variation in feedback data, such as additionalInformation, as opposed to another solution in which more feedback information would be specified up front in Configuration, which would be static if you wanted to initialize PinpointKit only once.

    Cons

    • Requires inheritance for a fairly basic customization.
    • Mix of some feedback details being specified up front (i.e. feedbackRecipients) and others at the time of sending. Maybe we should consider a FeedbackConfiguration struct instead of passing feedbackRecipients only through PinpointKit and Configuration initializers. Having only that as a solution, though, still doesn’t allow for up-to-the-moment variation (see the pro above).
    opened by mliberatore 5
  • Responding to PinpointKit submissions

    Responding to PinpointKit submissions

    What should the interface from which the app can respond to reports created via PinpointKit look like?

    In my quick-and-dirty attempt to rip out the email dependency from BugshotKit, I ended up with a delegate protocol that looks like:

    @protocol BugshotKitDelegate
    
    - (BOOL)bugshotKitShouldPresent;
    
    - (void)bugshotKitDidSubmit:(nonnull BSKSubmission *)submission;
    
    @end
    
    @interface BSKSubmission : NSObject
    
    @property (nonatomic, readonly, nonnull) NSString *appName;
    @property (nonatomic, readonly, nonnull) NSString *appVersion;
    @property (nonatomic, readonly, nonnull) NSString *modelIdentifier;
    @property (nonatomic, readonly, nonnull) NSString *systemVersion;
    @property (nonatomic, readonly, nonnull) UIImage *screenshot;
    @property (nonatomic, readonly, nonnull) NSString *log;
    
    @end
    

    In my implementation of this delegate callback, I present a custom compose sheet that posts to Trello. One tricky part was determining which view controller I should present this Trello composer from. Perhaps the PinpointKit delegate protocol should pass the view controller that it presented itself from, so the delegate can easily make use of it afterwards (I am imagining PinpointKit will recursively walk the view controller hierarchy to determine where it should present from?).

    opened by irace 5
Releases(1.5.0)
  • 1.5.0(Sep 18, 2020)

  • 1.4.0(Jun 5, 2020)

    • Add swift_version attribute to Podspec (#256)
    • Update to Swift 5 (#258)
    • Allow HTML body content in Emails (#259)
    • Fixed a bug that prevented the navigation bar title from being visible in Dark Mode on iOS (#272)
    Source code(tar.gz)
    Source code(zip)
  • 1.3.0(Oct 5, 2018)

  • 1.2.0(May 18, 2018)

    • Adds support for Swift 4.1 and Xcode 9.3.
    • Adds an alert upon failure to compose email.
    • Adds ability to specify the UIModalPresentationStyle used by FeedbackNavigationController.
    • Fixes issue with UIBarButtonItems changing font on highlight in iOS 11.
    • Fixes issue with missing fonts when installing PinpointKit using the manual setup instructions.
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Oct 9, 2017)

    This release adds support for Swift 4 and Xcode 9.

    • Fixes an issue where Photo permissions may be asked for prematurely.
    • Fixes an issue on iOS 11 where the Dismiss button of the Text Editor was too close to the title view.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Feb 7, 2017)

    This release adds support for Swift 3, including API changes reflecting the new naming guidelines, and additional entry points for customization and configuration.

    • Moves ScreenshotDetector to a subspec that is not included by default, so that clients need not set NSPhotoLibraryUsageDescription by default.
    • Changes access control to publicize additional properties and objects that were previously private or internal for better customization.
    • Adds an EditorDelegate API to allow clients to be informed of more events within the editor.
    • Adds FeedbackConfiguration to allow greater configuration of the feedback to be sent.
    • Uses iOS 10 as the base SDK, which negates the usage of SystemLogger on iOS 10+ since there is currently no generic way to read all system logs, as there was pre-iOS 10.
    • Removes defaultPinpointKit. Clients are now responsible for holding onto their own PinpointKit reference. Please refer to the README and Example project for code samples displaying this behavior.
    Source code(tar.gz)
    Source code(zip)
  • 0.9(Jun 10, 2016)

    This is a preview release of PinpointKit.

    PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots and logs using a simple gesture.

    Features

    • [x] Shake to trigger feedback collection
    • [x] Automatic, opt-in system log collection
    • [x] Add arrows, boxes, and text to screenshots to point out problems.
    • [x] Blur our sensitive information before sending screenshots
    • [x] Customize everything
      • [x] The color of the arrows, and boxes
      • [x] The text in the interface
      • [x] How and where your feedback is sent
    • [x] Absolutely free and open source
    • [x] No backend required
    Source code(tar.gz)
    Source code(zip)
Owner
Lickability
Designing & developing delightful apps. We’re a software studio crafting mobile products for our customers and clients. 👅🛠📱
Lickability
Switchboard - easy and super light weight A/B testing for your mobile iPhone or android app. This mobile A/B testing framework allows you with minimal servers to run large amounts of mobile users.

Switchboard - easy A/B testing for your mobile app What it does Switchboard is a simple way to remote control your mobile application even after you'v

Keepsafe 287 Nov 19, 2022
Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running in minutes. @buildasaur

Buildasaur Automatic testing of your Pull Requests on GitHub and BitBucket using Xcode Server. Keep your team productive and safe. Get up and running

Buildasaurs 774 Dec 11, 2022
Stub your network requests easily! Test your apps with fake network data and custom response time, response code and headers!

OHHTTPStubs OHHTTPStubs is a library designed to stub your network requests very easily. It can help you: test your apps with fake network data (stubb

Olivier Halligon 4.9k Dec 29, 2022
Lightweight touch visualization library in Swift. A single line of code and visualize your touches!

TouchVisualizer is a lightweight pure Swift implementation for visualising touches on the screen. Features Works with just a single line of code! Supp

Morita Naoki 851 Dec 17, 2022
Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class.

Freezer Freezer is a library that allows your Swift tests to travel through time by mocking NSDate class. Usage Once Freezer.start() has been invoked,

Sergey Petrov 8 Sep 24, 2022
T - A simple testing framework using closures and errors

t Quickly test expectations What is t? t is a simple testing framework using clo

OpenBytes 6 Nov 7, 2022
A simple and lightweight matching library for XCTest framework.

Match A simple and lightweight matching library for XCTest framework. Getting started Swift Package Manager You can add Match to your project by addin

Michał Tynior 6 Oct 23, 2022
Small library to easily run your tests directly within a Playground

[] (https://developer.apple.com/swift/) Build Status Branch Status master develop About PlaygroundTDD enables you to use TDD directly on Xcode Playgro

Whiskerz AB 317 Nov 22, 2022
Basic (simple) App for MacOS with simple functionality

Test Mac App Basic (simple) App for MacOS with simple functionality General Details Build : 1.0 Author Alias : gonewithharshwinds Brand : ADV Descript

Harsh ADV) 1 Dec 25, 2021
Test task application based on Swift using CoreData, Alamofire, AlamofireImage and CocoaPods

iTunes Search Test task application based on Swift using CoreData, Alamofire, AlamofireImage and CocoaPods Features ?? Searching music albums by name

Alexander Zhukov 0 Oct 31, 2021
Tapper - simple app for iOS and iPadOS allows a user to tap a button as many times as possible in 20 seconds

Tapper Table of Contents Description Screenshots Installation Usage Code Contact

Geoff Johnson 0 Mar 12, 2022
A Mac and iOS Playgrounds Unit Testing library based on Nimble.

Spry Spry is a Swift Playgrounds Unit Testing library based on Nimble. The best thing about Spry is that the API matches Nimble perfectly. Which means

Quick 327 Jul 24, 2022
View your app on different device and font sizes

Sizes reduces the time it takes to evaluate all of our apps possible device sizes, orientations and font combinations. With Sizes we'll avoid launchin

Marcos Griselli 1.2k Oct 27, 2022
Mock Alamofire and URLSession requests without touching your code implementation

Mocker is a library written in Swift which makes it possible to mock data requests using a custom URLProtocol. Features Requirements Usage Activating

WeTransfer 898 Dec 26, 2022
AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types.

AutoMocker Context AutoMocker is a Swift framework that leverages the type system to let you easily create mocked instances of your data types. Here's

Vincent Pradeilles 39 May 19, 2022
Erik is an headless browser based on WebKit. An headless browser allow to run functional tests, to access and manipulate webpages using javascript.

Erik Erik is a headless browser based on WebKit and HTML parser Kanna. An headless browser allow to run functional tests, to access and manipulate web

Eric Marchand 544 Dec 30, 2022
Marvel - Marvel Characters App using MVVM, and including unit tests

Marvel About The purpose of this project is to develop a app using MVVM, and inc

null 1 Mar 20, 2022
Bluepill is a reliable iOS testing tool that runs UI tests using multiple simulators on a single machine

Bluepill is a tool to run iOS tests in parallel using multiple simulators. Motivation LinkedIn created Bluepill to run its large iOS test suite in a r

Mobile Native Foundation 3.1k Jan 3, 2023
UITest helper library for creating readable and maintainable tests

UITestHelper General information When creating UI tests you will see that you are often repeating the same pieces of code. The UITestHelper library wi

Edwin Vermeer 56 Feb 20, 2022