# GIPHY SDK for iOS
## _Table of contents_
**Setup**
- [Requirements](#requirements)
- [CocoaPods](#cocoapods)
- [Swift Package Manager](#swift-package-manager)
- [Carthage](#carthage)
- [API Key](#configure-your-api-key)
- [Customization](#custom-ui)
**Templates**
- [GiphyViewController](#giphyviewcontroller)
- [Settings](#template-settings)
- [Media Types](#media-types)
- [Theme](#theme)
- [GiphyDelegate](#events)
**GPHMedia**
- [GPHMediaView](#gphmediaview)
- [Media IDs](#media-ids)
**Caching & Dependencies**
- [Caching](#caching)
- [Dependencies](#dependencies)
**The Grid**
- [GiphyGridController](#grid-only-and-the-giphygridcontroller-setup)
- [Presentation](#giphygridcontroller-presentation)
- [GPHContent](#giphygridcontroller-gphcontent)
- [GPHGridDelegate](#giphygridcontroller-gphgriddelegate)
**Clips (GIFs with Sound!) + Animated Text Creation**
- [Clips](https://github.com/Giphy/giphy-ios-sdk/blob/main/clips.md)
- [Animated Text Creation](https://github.com/Giphy/giphy-ios-sdk/blob/main/animate.md)
### Requirements
- iOS 13.0 or later
- A Giphy API key from the [Giphy Developer Portal](https://developers.giphy.com/dashboard/?create=true).
- Xcode 12 and later
### Github Example Repo
- Run the example app to see the GIPHY SDK in action with all of its configurations. Run `pod install` and set your API key [here](https://github.com/Giphy/giphy-ios-sdk-ui-example/blob/master/Swift/Example/ViewController.swift#L113) before building the example app.
- Open [issues or feature requests](https://github.com/Giphy/giphy-ios-sdk-ui-example/issues)
- View [releases](https://github.com/Giphy/giphy-ios-sdk-ui-example/releases)
### CocoaPods
Add the GiphyUISDK to your Podfile like so:
```swift
target "YourAppTarget" do
pod 'Giphy'
end
```
**Note**: for pure Objective-C projects, add an empty swift file to your project and choose `Create the Bridging Header` when prompted by Xcode. This allows static libraries to be linked.
### Swift Package Manager
Add a new Swift Package to your app linking this repo (`https://github.com/Giphy/giphy-ios-sdk`).
Swift Package Manager is supported for versions 2.1.3 and later.
### Carthage
We are currently unable to distribute the GIPHY SDK through Carthage. If you are using Carthage, simply drag `GiphyUISDK.xcframework` into your project.
You will also have to add [webp support](https://github.com/SDWebImage/libwebp-Xcode) to your project.
### Configure your API key
First things first, be sure to import:
```swift
import GiphyUISDK
```
Configure your API key. Apply for a new __iOS SDK__ key [here](https://developers.giphy.com/dashboard/). Please remember, you should use a separate key for every platform (Android, iOS, Web) you add our SDKs to.
```swift
Giphy.configure(apiKey: "your ios sdk key here")
```
## Custom UI
We offer two solutions for the SDK user interface - pre-built templates which handle the entirety of the GIPHY experience, and a [Grid-Only implementation](https://developers.giphy.com/docs/sdk#grid) which allows for endless customization.
See [customization](https://developers.giphy.com/docs/sdk#grid) to determine what's best for you.
_Skip ahead to [Grid-Only section](#grid-only-and-the-giphygridcontroller-setup)_
### GiphyViewController
Create a new `GiphyViewController`, which takes care of most of the magic.
```swift
let giphy = GiphyViewController()
```
Create a new `GiphyViewController` every time you want to show GIPHY (maintaining a reference to the same `GiphyViewController` object isn't necesssary and can impact performance and lead to unexpected results)
## Template Settings
### _Media Types_
Set the content type(s) you'd like to show by setting the `mediaTypeConfig` property, which is an array of `GPHContentType`s.
```swift
giphy.mediaTypeConfig = [.gifs, .stickers, .text, .emoji]
```
Objective-C:
```Objective-C
[giphy setMediaConfigWithTypes: [[ NSMutableArray alloc] initWithObjects:
@(GPHContentTypeGifs), @(GPHContentTypeStickers), @(GPHContentTypeText), @(GPHContentTypeEmoji), nil ] ];
```
### _Recently Picked_
As of `v1.2.5`, you can add an additional `GPHContentType` to the `mediaTypeConfig` array: `.recents`
```swift
giphy.mediaTypeConfig = [.gifs, .stickers, .recents]
```
GIFs that are selected by the user are automatically added to the recents tab, which is only displayed if the user has previously picked a gif.
Users can remove gifs from recents with a long-press on the GIF in the recents grid.
### _Theme_
Set the theme type (`GPHThemeType`) to be `.dark`, `.light`, `.lightBlur`, `.darkBlur` or `.automatic`. The `automatic` option follows the current Dark Mode setting of the device.
```swift
giphy.theme = GPHTheme(type: .lightBlur)
```
For video editing apps, we recommend trying out `.lightBlur` or `.darkBlur` themes.
### _Extending GPHTheme_
As of version 1.2.8, you can also subclass `GPHTheme` to override visual properties like font and colors, so as to apply the visual language of your app.
```swift
public class CustomTheme: GPHTheme {
public override init() {
super.init()
self.type = .light
}
public override var textFieldFont: UIFont? {
return UIFont.italicSystemFont(ofSize: 15.0)
}
public override var textColor: UIColor {
return .black
}
}
```
Version 2.2.5 offers a wider range of colors for customization. We have made modifications to the color names, but we have prepared a [visual scheme](https://github.com/Giphy/giphy-ios-sdk/blob/main/assets/iOS_theme_scheme.pdf) to assist you with this update.
```swift
public class ExampleTheme: GPHTheme {
public override init() {
super.init()
self.type = .automatic
}
public override var searchPlaceholderTextColor: UIColor {
switch mode {
case .dark, .darkBlur:
return .blue
case .light, .lightBlur:
return .green
default:
return .clear
}
}
var mode: GPHThemeType {
if case .automatic = type {
if isDarkMode {
return .dark
}
return .light
}
return type
}
}
```
### _Additional Settings_
- **Sticker Column Count**: We provide the option to set the number of columns for stickers and text. Possible `GPHStickerColumnCount`values are `.two`, `.three`. and `.four`. We recommend going for 3 or 4 columns when leveraging the blur `GPHThemeType`.
```
giphy.stickerColumnCount = GPHStickerColumnCount.three
```
- **Confirmation screen**: we provide the option to show a secondary confirmation screen when the user taps a GIF, which shows a larger rendition of the asset.
```swift
giphy.showConfirmationScreen = true
```
- **Rating**: set a specific content rating for the search results. Default `ratedPG13`.
```swift
giphy.rating = .ratedPG13
```
- **Rendition**: option to select the rendition type for the grid. Default `fixedWidth`.
```swift
giphy.renditionType = .fixedWidth
```
- **Localization**: option to choose whether or not to localize the search results based on phone settings. Default `false` will set the language to `en`.
```swift
giphy.shouldLocalizeSearch = false
```
- **Tray Height**: height for the tray's "snap point" as a ratio of the `GiphyViewController`'s height. Default `0.7`
```swift
GiphyViewController.trayHeightMultiplier = 0.7
```
### _Presentation_
Present the `GiphyViewController` and watch as the GIFs start flowin'.
```swift
present(giphy, animated: true, completion: nil)
```
### _Events_
Set the delegate and conform to the `GiphyDelegate` protocol to handle GIF selection.
```swift
giphy.delegate = self
```
```swift
extension YourController: GiphyDelegate {
func didSelectMedia(giphyViewController: GiphyViewController, media: GPHMedia) {
// your user tapped a GIF!
giphyViewController.dismiss(animated: true, completion: nil)
}
func didDismiss(controller: GiphyViewController?) {
// your user dismissed the controller without selecting a GIF.
}
}
```
From there, it's up to you to decide what to do with the GIF!
### _GPHMediaView_
Create a `GPHMediaView` to display the media:
```swift
let mediaView = GPHMediaView()
mediaView.media = media
```
Use the media's `aspectRatio` property to size the view:
```swift
let aspectRatio = media.aspectRatio
```
If you want to build your own view to display a GIF, grab a URL to the asset like so:
```swift
let webpURL = media.url(rendition: .original, fileType: .webp)
let gifURL = media.url(rendition: .fixedWidth, fileType: .gif)
let vidURL = media.url(rendition: .fixedWidth, fileType: .mp4)
let url = URL(string: gifURL)
```
### _Media IDs_
In a messaging app context, you may want to send media `id`s rather than `GPHMedia` objects or image assets.
Obtain a `GPHMedia`'s `id` property via `media.id`
On the receiving end, obtain a `GPHMedia` from the `id` like so:
```swift
GiphyCore.shared.gifByID(id) { (response, error) in
if let media = response?.data {
DispatchQueue.main.sync { [weak self] in
self?.mediaView.media = media
}
}
}
```
### _Caching_
We use [URLCache](https://developer.apple.com/documentation/foundation/urlcache) to cache media assets, which reduces unnecessary image requests and loading times.
The `URLCache` disk and memory components are both limited to 300 mb by default, but you can set them to any values you’d like:
```swift
// set to 300 mb
GPHCache.shared.cache.diskCapacity = 300 * 1000 * 1000
GPHCache.shared.cache.memoryCapacity = 300 * 1000 * 1000
```
Note: We *don't* automatically clear the cache when the `GiphyViewController` is dismissed.
Manually clear the cache by calling `GPHCache.shared.clear()` to clear the cache
The cache stores`Data` objects for the images (the SDK displays .webp files by default). You can get the raw image data yourself via:
```swift
guard let url = media.url(rendition: .fixedWidth, fileType: .webp) else { return }
GPHCache.shared.downloadAssetData(url) { (data, error) in
}
```
#### *Dependencies*
[YYImage](https://github.com/ibireme/YYImage): GIF playback
[libwebp](https://github.com/webmproject/libwebp): webp playback
#### *Buttons*
Download the Sketch file [here](https://s3.amazonaws.com/sdk.mobile.giphy.com/design/GIPHY-SDK-UI-Kit.sketch) if you're looking for a great button icon to prompt the GIPHY SDK experience.
## Grid-Only and the GiphyGridController Setup
The following section refers to the Grid-Only solution of the SDK. Learn more [here](https://developers.giphy.com/docs/sdk#grid)
_See the [Template section](#templates-via-giphyviewcontroller) for template setup instructions._
The `GiphyGridController` takes care of requesting content from the GIPHY API, loading, caching, and rendering images in a customizable grid, and leaves the rest of the experience up to you.
The `GiphyGridController` offers more customization of the grid than the `GiphyViewController`, via the `numberOfTracks`, `cellPadding`, and `direction` properties.
Create a new grid controller:
```
let gridController = GiphyGridController()
```
Customize the grid design:
```
// space between cells
gridController.cellPadding = 2.0
// the scroll direction of the grid
gridController.direction = .vertical
// the number of "tracks" is the span count. it represents num columns for vertical grids & num rows for horizontal grids
gridController.numberOfTracks = 3
// hide the checkered background for stickers if you'd like (true by default)
gridController.showCheckeredBackground = false
gridController.view.backgroundColor = .lightGray
// by default, the waterfall layout sizes cells according to the aspect ratio of the media
// the fixedSizeCells setting makes it so each cell is square
// this setting only applies to Stickers (not GIFs)
gridController.fixedSizeCells = true
```
### GiphyGridController: Presentation
Unlike the `GiphyViewController`, the `GiphyGridController` is not by itself a fully functional component, and must exist alongside other UI in order to offer a meaningful user experience. We recommend embedding the `GiphyGridController` inside of another `UIViewController` by adding it as a child view controller, adding its subview, and constraining it according to your design.
*Important*
For performance reasons, a new `GiphyGridController` should be created _every time_ the Giphy search experience is presented, and the instance should be always set to nil when it is dismissed. Ensure that there is only ever one instance of a `GiphyGridController` allocated at a given screen - multiple instances of `GiphyGridController`s may not be added to the same screen.
```swift
addChild(gridController)
view.addSubview(gridController.view)
gridController.view.translatesAutoresizingMaskIntoConstraints = false
gridController.view.leftAnchor.constraint(equalTo: view.safeLeftAnchor).isActive = true
gridController.view.rightAnchor.constraint(equalTo: view.safeRightAnchor).isActive = true
gridController.view.topAnchor.constraint(equalTo: view.safeTopAnchor).isActive = true
gridController.view.bottomAnchor.constraint(equalTo: view.safeBottomAnchor).isActive = true
gridController.didMove(toParent: self)
```
### GiphyGridController: GPHContent
The `GiphyGridController` comes with a new class `GPHContent`. A `GPHContent` describes a content request to the Giphy API.
Create content objects with `GPHContent` class methods, like so:
#### Trending
```
let trendingGIFs = GPHContent.trending(mediaType: .gif)
let trendingStickers = GPHContent.trending(mediaType: .sticker)
let trendingText = GPHContent.trending(mediaType: .text)
```
#### Emoji
```
let emoji = GPHContent.emoji
```
#### Search
```
let search = GPHContent.search(withQuery: "Hello", mediaType: .gif, language: .english)
```
#### Recents
Show GIFs that the user has previously picked.
```
let recentlyPicked = GPHContent.recents
```
Only show a "recents" tab if there are any recents. Get the number of recents via:
```
let numberOfRecents = GPHRecents.count
```
Optionally, we also provide the option to clear the set of recents:
```
GPHRecents.clear()
```
### Updating the content
Set the grid controller's `content` property and call update:
```
gridController.content = GPHContent.search(withQuery: "Sup", mediaType: .text, language: .english)
gridController.update()
```
### GiphyGridController: GPHGridDelegate
Similar to the `GiphyDelegate`, the `GPHGridDelegate` is the mechanism for responding to gif selection events in the grid.
Conform to the `GPHGridDelegate` and set the delegate.
```
gridController.delegate = self
```
```
extension ViewController: GPHGridDelegate {
func contentDidUpdate(resultCount: Int) {
print("content did update")
}
func didSelectMedia(media: GPHMedia, cell: UICollectionViewCell) {
print("did select media")
}
}
```
### Data Collected by our SDK
#### Details
Apple will require developers to provide information about their app’s privacy practices in App Store Connect, including the practices of third-party partners whose code is integrated into their app. To make this process easier for you, we’ve provided the following list of boxes you will be required check when submitting your app to the App Store if your app integrates the GIPHY SDK.
_We deeply respect the privacy of your users and only collect anonymized information about GIPHY use in order to improve the service. If you have any questions or concerns about GIPHY’s data collection practices, please reach out to developers@giphy.com_
| Title | Description | Data use | Linked to user | Tracking |
| --- | --- | --- | --- | --- |
| Search History | Information about searches performed in the app | Analytics, Product Personalization, App Functionality | No | No |
| Product Interaction | Such as app launches, taps, clicks, scrolling information, music listening data, video views, saved place in a game, video, or song, or other information about how the user interacts with the app | Analytics, Product Personalization, App Functionality| No | No |