Drop-in replacement for system() in iOS programs

Related tags

Utility ios_system
Overview

ios_system: Drop-in replacement for system() in iOS programs

Platform: iOS Build Status Twitter

When porting Unix utilities to iOS (vim, TeX, python...), sometimes the source code executes system commands, using system() calls. These calls are rejected at compile time, with: error: 'system' is unavailable: not available on iOS.

This project provides a drop-in replacement for system(). Simply add the following lines at the beginning of you header file:

extern int ios_system(char* cmd);
#define system ios_system

link with the ios_system.framework, and your calls to system() will be handled by this framework.

Commands available: shell commands (ls, cp, rm...), archive commands (curl, scp, sftp, tar, gzip, compress...) plus a few interpreted languages (python, lua, TeX). Scripts written in one of the interpreted languages are also executed, if they are in the $PATH.

The commands available are defined in two dictionaries, Resources/commandDictionary.plist and Resources/extraCommandsDictionary.plist. At startup time, ios_system loads these dictionaries and enables the commands defined inside. You will need to add these two dictionaries to the "Copy Bundle Resources" step in your Xcode project.

Each command is defined inside a framework. The framework is loaded when the command is called, and released after the command exits. Frameworks for small commands are in this project. Frameworks for interpreted languages are larger, and available separately: python, lua and TeX.

Network-based commands (nslookup, dig, host, ping, telnet) are also available as a separate framework, network_ios. Place the compiled library with the other libraries and add it to the embedded libraries of your application.

This ios_system framework has been successfully integrated into four shells, Blink, OpenTerm, Pisth and LibTerm, an editor, iVim and a TeX-writing app, TeXable. Each time, it provides a Unix look-and-feel (well, mostly feel).

Issues: In iOS, you cannot write in the ~ directory, only in ~/Documents/, ~/Library/ and ~/tmp. Most Unix programs assume the configuration files are in $HOME. So either you redefine $HOME to ~/Documents/ or you set configuration variables (using setenv) to some other place. This is done in the initializeEnvironment() function.

Here's what I have:

setenv PATH = $PATH:~/Library/bin:~/Documents/bin
setenv PYTHONHOME = $HOME/Library/
setenv SSH_HOME = $HOME/Documents/
setenv CURL_HOME = $HOME/Documents/
setenv HGRCPATH = $HOME/Documents/.hgrc/
setenv SSL_CERT_FILE = $HOME/Documents/cacert.pem

Your Mileage May Vary. Note that iOS already defines $HOME and $PATH.

Installation:

The easy way: (Xcode 12 and above) ios_system is available as a set of binary frameworks. Add this project as "Swift Package dependency", and link and embed the frameworks as you need them.

The semi-hard way:

Type swift run --package-path xcfs build. This will download all the requirements (libssh2 and openssl) and build all the ios_system XcFrameworks, in the .build directory.

The hard way:

  • Open the Xcode project ios_system.xcodeproj and hit build. This will create the ios_system framework, ready to be included in your own projects.
  • Compile the other targets as well: files, tar, curl, awk, shell, text, ssh_cmd. This will create the corresponding frameworks.
  • Alternatively, type xcodebuild -project ios_system.xcodeproj -alltargets -sdk iphoneos -configuration Release -quiet to build all the frameworks.
  • If you need python, lua, TeX or network_ios, download the corresponding projects and compile them. All these projects need the ios_system framework to compile.

Integration with your app:

  • Link your application with the ios_system.framework framework.
  • Embed (but don't link) the frameworks corresponding to the commands you need (libtar.dylib if you need tar, libfiles.dylib for cp, rm, mv...).
  • Add the two dictionaries, Resources/commandDictionary.plist and Resources/extraCommandsDictionary.plist to the "Copy Bundle Resources" step in your Xcode project.

Basic commands:

The simplest way to integrate ios_system into your app is to just replace all calls to system() with calls to ios_system(). If you need more control and information, the following functions are available:

  • initializeEnvironment() sets environment variables to sensible defaults.
  • ios_executable(char* inputCmd) returns true if inputCmd is one of the commands defined inside ios_system.
  • NSArray* commandsAsArray() returns an array with all the commands available, if you need them for helping users.
  • NSString* commandsAsString() same, but with a NSString*.
  • NSString* getoptString(NSString* command) returns a string containing all accepted flags for a given command ("dfiPRrvW" for "rm", for example). Letters are followed by ":" if the flag cannot be combined with others.
  • NSString* operatesOn(NSString* command) tells you what this command expects as arguments, so you can auto-complete accordingly. Return values are "file", "directory" or "no". For example, "cd" returns "directory".
  • int ios_setMiniRoot(NSString* mRoot) lets you set the sandbox directory, so users are not exposed to files outside the sandbox. The argument is the path to a directory. It will not be possible to cd to directories above this one. Returns 1 if succesful, 0 if not.
  • FILE* ios_popen(const char* inputCmd, const char* type) opens a pipe between the current command and inputCmd. (drop-in replacement for popen).

More advance control:

replaceCommand: replaceCommand(NSString* commandName, int (*newFunction)(int argc, char *argv[]), bool allOccurences) lets you replace an existing command implementation with your own, or add new commands without editing the source.

Sample use: replaceCommand(@"ls", gnu_ls_main, true);: Replaces all calls to ls to calls to gnu_ls_main. The last argument tells whether you want to replace only the function associated with ls (if false) or all the commands that used the function previously associated with ls(if true). For example, compress and uncompress are both done with the same function, compress_main (and the actual behaviour depends on argv[0]). Only you can know whether your replacement function handles both roles, or only one of them.

If the command does not already exist, your command is simply added to the list.

addCommandList: NSError* addCommandList(NSString* fileLocation) loads several commands at once, and adds them to the list of existing commands. fileLocation points to a plist file, with the same syntax as Resources/extraCommandsDictionary.plist: the key is the command name, and is followed by an Array of 4 Strings: name of the framework, name of the function to call, list of options (in getopt() format) and what the command expects as argument (file, directory, nothing). The last two can be used for autocomplete. The name of the framework can be MAIN if your command is defined in your main program (equivalent to the RTLD_MAIN_ONLY option for dlsym()), or SELF if it is defined inside ios_system.framework (equivalent to RTLD_SELF).

Example:

<key>rlogin</key>
  <array>
    <string>network_ios.framework/network_ios</string>
    <string>rlogin_main</string>
    <string>468EKLNS:X:acde:fFk:l:n:rs:uxy</string>
    <string>no</string>
  </array>

ios_execv(const char path, char const argv[]): executes the command in argv[0] with the arguments argv (it doesn't use path). It is not a drop-in replacement for execv because it does not terminate the current process. execv is usually called after fork(), and execv terminates the child process. This is not possible in iOS. If dup2 was called before execv to set stdin and stdout, ios_execv tries to do the right thing and pass these streams to the process started by execv.

ios_execve also exists, and stores the environment.

Adding more commands:

ios_system is OpenSource; you can extend it in any way you want. Keep in mind the intrinsic limitations:

  • Sandbox and API limitations still apply. Commands that require root privilege (like traceroute) are impossible.
  • Inside terminals we have limited interaction. Apps that require user input are unlikely to get it, or with no visual feedback. That could be solved, but it is hard.

To add a command:

  • (Optional) create an issue: https://github.com/holzschu/ios_system/issues That will let others know you're working on it, and possibly join forces with you (that's the beauty of OpenSource).
  • find the source code for the command, preferrably with BSD license. Apple OpenSource is a good place to start. Compile it first for OSX, to see if it works, and go through configuration.
  • make the following changes to the code:
    • change the main() function into command_main().
    • include ios_error.h.
    • link with ios_system.framework; this will replace most function calls by ios_system version (exit, warn, err, errx, warnx, printf, write...)
    • replace calls to isatty() with calls to ios_isatty().
    • usually, this is enough for your command to compile, and sometimes to run. Check that it works.
    • if you have no output: find where the output happens. Within ios_system, standard output must go to thread_stout. libc_replacement.c intercepts most of the output functions, but not all.
    • if you have issues with input: find where it happens. Standard input comes from thread_stdin.
    • make sure you initialize all variables at startup, and release all memory on exit.
    • make all global variables thread-local with __thread, make sure local variables are marked with static.
    • make sure your code doesn't use commands that don't work in a sandbox: fork, exec, system, popen, isExecutableFileAtPath, access... (some of these fail at compile time, others fail silently at run time).
    • compile the digital library, add it to the embedded frameworks of your app.
    • Edit the Resources/extraCommandsDictionary.plist to add your command, and run.
    • That's it.
    • Test a lot. Side effects can appear after several launches.

Frequently asked commands: here is a list of commands that are often requested, and my experience with them:

  • ping, nslookup, telnet: now provided in the network_ios package.
  • traceroute and most network analysis tools: require root privilege, so impossible inside a sandbox.
  • unzip: use tar -xz.
  • sh, bash, zsh: shells are hard to compile, even without the sandbox/API limitations. They also tend to take a lot of memory, which is a limited asset.
  • git: WorkingCopy does it very well, and you can transfer directories to your app, then transfer back to WorkingCopy. Also difficult to compile.

Licensing:

ios_system itself is released under the Revised BSD License (3-clause BSD license). Foe the other tools, I've used the BSD version as often as possible:

Using BSD versions has consequences on the flags and how they work. For example, there are two versions of sed, the BSD version and the GNU version. They have roughly the same behaviour, but differ on -i (in place): the GNU version overwrites the file if you don't provide an extension, the BSD version won't work unless you provide the extension to use on the backup file (and will backup the input file with that extension).

Comments
  • Support for UTF-8 encoding

    Support for UTF-8 encoding

    OpenTerm passes UTF-8 commands to ios_system, and expects UTF-8 output from commands. However, argument parsing & command parsing converts the string to ASCII, which causes data loss.

    Try: echo 😀 in OpenTerm to see results.

    opened by ian-mcdowell 14
  • python: command not found

    python: command not found

    Hi holzschu :) It's my first time trying out ios_system and everything seems to be working fine except python.

    I linked python3_ios framework obtained from here to the project and transferred the python scripts to the library. For some reason ios_system is not recognising it and always show command not found. What am I missing?

    opened by bummoblizard 10
  • Make ios_system thread-safe

    Make ios_system thread-safe

    As requested by @yury and @IMcD23 : ios_system() should be made thread-safe, allowing people to launch commands in multiple tabs.

    This is not trivial, since making current_command_root_thread a thread-local variable results in it not being set in most threads, and ios_kill() having no thread ID available to kill.

    Ideally, I'd like an implementation that is compatible with current applications.

    Making ios_system itself thread-safe will leave the issue of some commands being not thread-safe themselves (2 "python" in separate tabs will almost certainly not work).

    enhancement fix committed 
    opened by holzschu 9
  • Calling ios_kill() may cause a crash

    Calling ios_kill() may cause a crash

    Hi, @holzschu . I am trying to call pdflatex with ios_system framework. It works fine. However, when compiling large files, if I call the ios_kill method to end the compilation, the application crashes. 1 The problem may be in line 1963 of ios_system.m. There is something wrong with the function pointer of the signal handler.

    opened by 12345CPZ 8
  • Break up into separate dylibs

    Break up into separate dylibs

    I'd suggest building each command as a dynamic library (either .dylib or .framework), and lazy loading them at runtime.

    As noted in the README, all the code for all of the commands is loaded into memory at app launch. This seems wasteful & unnecessary, and probably won't scale too well when adding more commands over time.

    Additionally, it looks like they are currently being built into a single Xcode target. It'd be great if each command was its own target, with defined inputs/outputs (i.e. build these source files into this dylib). That way it's easier to pick & choose, and scales better.

    enhancement help wanted 
    opened by ian-mcdowell 8
  • using openTerm on my iPad

    using openTerm on my iPad

    Hi !

    I am not able to go around that ‘permission denied’ 👎

    Could you give me a hand ?

    Thanks for your job ! Regards, François

    iPad de François: ls iPad de François: cd / cd: /: permission denied

    iPad de François: date Sat Jan 20 13:33:01 CET 2018

    iPad de François: ? awk, cat, cd, chflags, chksum, clear, compress, cp, curl, date, du, echo, egrep, env, fgrep, grep, gunzip, gzip, help, link, ln, ls, mkdir, mv, printenv, pwd, readlink, rm, rmdir, scp, sed, setenv, sftp, stat, sum, tar, touch, tr, uname, uncompress, unsetenv, uptime, wc, whoami

    iPad de François: cd .. cd: ..: permission denied

    iPad de François: login login: command not found

    iPad de François: man ls man: command not found

    iPad de François: uname Darwin

    iPad de François: whoami mobile

    iPad de François: cd /var cd: /var: permission denied

    iPad de François: cd /var/mobile cd: /var/mobile: permission denied

    iPad de François: cd /var/mobile/Containers cd: /var/mobile/Containers: permission denied

    iPad de François: cd /var/mobile/Containers/Data cd: /var/mobile/Containers/Data: permission denied

    iPad de François: cd /var/mobile/Containers/Data/Application cd: /var/mobile/Containers/Data/Application: permission denied

    iPad de François:

    opened by passereve 7
  • New build system

    New build system

    Pre:

    I think Xcode builtin spm support is very sad.

    1. If you delete DerivedData you have to close Xcode and redownload all deps (with xcframeworks they are really heavy)
    2. Can't actually link to XCFramework (you have to use abs path to derived data)
    3. Really poor and only one way to edit deps via UI
    4. Updates not reliable (sometimes you have to delete DerivedData)

    I propose to use Package.swift directly and reference deps XCFrameworks from .build/artifacts

    I put Package swift in xcfs (read as xcframeworks) folder. And change reps in targets to xcfs/.build/artifacts/xcfs/.... so we have relative paths to XCFrameworks now.

    Another improvements:

    1. I use archives for building frameworks, so we have dsyms and call safe layer for compatibility
    2. xcframeworks now have dsyms
    3. I added GitHub Actions, so we can publish sha for libs on release

    Other thoughts and plans:

    1. This is work in progress, I just want to show you direction and get feedback early
    2. Pland to upgrade to openssl 1.1.1i. (I have lib compiled, but I need to update ssh_cmd)
    3. We need to drop i386 and include arm64 from simulators
    opened by yury 6
  • Logic of waitpid seems incorrect

    Logic of waitpid seems incorrect

    https://github.com/holzschu/ios_system/blob/88fb6f9bd1e22e3861b238a999f557454ffbfdb1/libc_replacement.c#L219-L228

    As shown above, it is possible that the related thread had already been done when waitpid is called, which will make the code jump to line 224. But in this case, waitpid should return the pid, rather than -1 as in line 227.

    opened by terrychou 6
  • scp fixes for Blink. Grab remote port setting from config and try to use blink id_rsa and id_dsa keys

    scp fixes for Blink. Grab remote port setting from config and try to use blink id_rsa and id_dsa keys

    Hi @holzschu!

    Not sure I did right patching thing. But this patch adds port configuration from blink hosts config for scp.

    #ifdef BLINKSHELL // get user and host from Blinkshell config
        if ((strcmp(protop, "scp") == 0) || (strcmp(protop, "sftp") == 0)) {
            BKHosts *host;
            if (host = [BKHosts withHost:[NSString stringWithUTF8String:conn->host.name]]) {
                if (host.hostName) conn->host.name = [host.hostName UTF8String];
                if ([host.user length]) {
                    *userp = strdup([host.user UTF8String]);
                }
                // grab remote port from host settings too
                if (host.port.intValue) {
                    conn->remote_port = host.port.intValue;
                }
            }
        }
    #endif
    
    opened by yury 6
  • Can't compile current iVim

    Can't compile current iVim

    I'm having trouble compiling the latest master version of iVim I'm doing the same steps that worked before. The compilation ends with the error message

    CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
        cd /Users/goerz/Documents/Programming/iVim/iVim
        export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
        export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
        export SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk
        /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc -incremental -module-name iVim -Onone -enforce-exclusivity=checked -DDEBUG -sdk [...]
    
    <unknown>:0: error: no such file or directory: '/Users/goerz/Documents/Programming/iVim/iVim/URLRealizer.swift'
    <unknown>:0: error: no such file or directory: '/Users/goerz/Documents/Programming/iVim/iVim/ArgumentToken.swift'
    <unknown>:0: error: no such file or directory: '/Users/goerz/Documents/Programming/iVim/iVim/URLOpener.swift'
    Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
    

    The swift files it complains about are actually in /Users/goerz/Documents/Programming/iVim/iVim/iVim (an extra iVim). I've tried copying the entire content of that directory up one level, to the path where Xcode seems to be asking for.

    This gets me further in the compilation, but then the linker fails with

    ld: illegal data reference in _Py_NoSiteFlag to thread local variable _Py_NoSiteFlag in dylib /Users/goerz/Documents/Programming/iVim/iVim/Frameworks/Python_ios.framework/Python_ios for architecture arm64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    Any ideas?

    opened by goerz 6
  • whois command

    whois command

    I found this command useful.

    I tried to port it myself this time.

    This command is in adv_cmds, don't find it framework. so, I test it with in files.framework

    And I don't get how to create patch file. So this is my whois.c file I hope it helps.

    fix committed 
    opened by yury 6
  • Change dependency on commands source code to submodules

    Change dependency on commands source code to submodules

    When the project was started, the only way to get code from opensource.apple.com was by downloding tar archives.

    Now, most commands from Apple Opensource have a git server (e.g. https://github.com/apple-oss-distributions/file_cmds/tree/file_cmds-400) Changing dependencies to submodules will allow continuous updates of shell commands.

    enhancement 
    opened by holzschu 0
  • Build fails (when using as package dependency) , build target iPad simulator

    Build fails (when using as package dependency) , build target iPad simulator

    I've created a quite simple test swift project with quite nothing in it. Just imported iOS_system and added ios_system framework as package dependency. When hitting build it runs into errors. Perl, PerlA, PerlB cannot be build for iPad simulator.

    When checking files, only in perl simulator folder are missing.

    Is it possible to fix this or is there a workaround? I tried to delete perl from package description and it compiles standalone, but dependency in my project does not take this change.

    opened by wit19 1
  • Adding

    Adding "btfs", go-btfs. Bounty $$ offer

    Hello everyone! I'm attempting to add the following command (app) to a-shell: https://github.com/bittorrent/go-btfs

    go-btfs aims to decentralize cloud storage and I'm currently using it for a project called dCloud.Being a go program, arm64-darwin binary or c-shared library are available . I already tested it for MacOS, Android, Linux and Windows and its working flawlessly, however I'm new to iOS development and having some struggles to get it to work on iOS.

    I came across to a-shell and looks like I might have a chance to get it to work without needing to make tons of source code changes, but don't have the necessary know-how to quickly get started and test the building , making the necessary adjustments in Xcode, etc. That's why I'm opening this ticket offering a bounty for anyone willing to support with any of the following options:

    • Support me on configuring / building and basic testing on my own bench through this ticket (Successful build, no matter if it doesn't run properly at the end) --> $100

    • Support me on configuring / building and basic testing on my own bench through this ticket (Successfully build with some issues) --> $150

    • Configuring and building either on my bench or your own bench with a successful build and minor to none issues --> $800

    Any kind of support is of course more than welcomed and can offer tips for hints, recommendations, etc.

    Note 1: Bounty will go for the person/team who brings key information to get a successful build running go-btfs on a-shell (not rooted iOS)

    Note 2: all payments will go trough cryptocurrency: TRX, BTT or Monero.

    I'll keep tying myself in the meantime

    Thanks in advance!

    opened by simbadMarino 0
  • [Documentation] Link to `python` framework is for `python2`

    [Documentation] Link to `python` framework is for `python2`

    Summary

    • python 2 is no longer under development.
    • Apps using ios_system seem to have access to python3.
    • The links to the python framework in the README seems to be a link to a python 2 repository.

    Thank you for making this project! Please update the link!

    opened by personalizedrefrigerator 0
  • [Request] Update curl to support TLS v1.3

    [Request] Update curl to support TLS v1.3

    Currently, ios_system's curl can't download HTTPS site's contents using TLS v1.3.

    I think that you built curl 7.51.0 with --with-darwinssl flag. If so, is it possible to update curl to 7.56.1 or later?

    curl with darwinssl has supported TLS v1.3 since 7.56.1.

    opened by kkk669 1
Releases(v3.0.2)
Owner
Nicolas Holzschuch
Nicolas Holzschuch
UIPredicateEditor aims to be come a drop-in replacement of NSPredicateEditor for iOS, iPadOS and Mac Catalyst targets.

UIPredicateEditor UIPredicateEditor aims to be come a drop-in replacement of NSPredicateEditor for iOS, iPadOS and Mac Catalyst targets. The plan is t

Nikhil Nigade 1 Jun 6, 2022
A drop-in `NSComboButton` replacement with pre macOS 13 support.

DSFComboButton A drop-in NSComboButton replacement control with pre macOS 13 support. For when you want to adopt NSComboButton but have to maintain co

Darren Ford 8 Nov 9, 2022
ETFKit - Designed to be a drop-in replacement for JSONDecoder/JSONEncoder

ETFKit Encoder/decoder for Erlang's External Term Format (version 131). Designed to be a drop-in replacement for JSONDecoder/JSONEncoder. Simply repla

Swiftcord 2 Jun 10, 2022
Mouse Finder is a fun replacement for the system Finder icon in the Dock.

Mouse Finder Mouse Finder is a fun replacement for the system Finder icon in the Dock. It mostly works exactly like the system icon, with one importan

Neil Sardesai 432 Dec 22, 2022
macOS system library in Swift

SystemKit A macOS system library in Swift based off of libtop, from Apple's top implementation. For an example usage of this library, see dshb, a macO

null 323 Jan 5, 2023
ALO sync allows you to sync resources form an ALO endpoint to your macOS file system.

ALO sync allows you to sync resources form an ALO endpoint to your macOS file system. Prerequisites macOS 11 No support for search* No suppor

Lawrence Bensaid 2 Jan 22, 2022
MetricTime is designed to be one universal timekeeping system that eliminates the hassle of calculating time since most of its convertions as simple as converting meters to centimeters

MetricTime MetricTime is designed to be one universal timekeeping system that eliminates the hassle of calculating time since most of its convertions

Adrian Edwards 4 Feb 10, 2022
Swift System, battery included.

System Extras A complimentary set of extensions to Swift System. Our goals are: Feel natural to use in conjunction to existing System APIs Provide mis

Daniel Duan 5 Oct 20, 2022
Ios-mod-extract - iOS mod extract with swift

DIOExtract Example To run the example project, clone the repo, and run pod insta

Victor Freitas 3 Jun 14, 2022
IOS-Bootcamp-Examples - Learn to Swift while building apps - With IOS Development Bootcamp

IOS-Bootcamp-Examples Learn to Swift while building apps - With IOS Development

Bilge Çakar 9 Dec 21, 2022
iOS helper library that contains commonly used code in Uptech iOS projects

iOS helper library that contains commonly used code in Uptech iOS projects.

Uptech 1 Apr 1, 2022
Ethereum Wallet Toolkit for iOS - You can implement an Ethereum wallet without a server and blockchain knowledge.

Introduction EtherWalletKit is an Ethereum Wallet Toolkit for iOS. I hope cryptocurrency and decentralized token economy become more widely adapted. H

Sung Woo Chang 136 Dec 25, 2022
Generate a privacy policy for your iOS app

PrivacyFlash Pro To easily run PrivacyFlash Pro get the latest packaged release. Learn more about PrivacyFlash Pro in our research paper. PrivacyFlash

privacy-tech-lab 141 Dec 22, 2022
Tweak your iOS app without recompiling!

SwiftTweaks Adjust your iOS app on the fly without waiting to re-compile! Your users won’t see your animation study, Sketch comps, or prototypes. What

Khan Academy 1.4k Dec 28, 2022
Updeto is a simple package that help update checker for iOS Apps

Updeto is a simple package that will help you to check if the currently installed version is the same as the latest one available on App Store.

Manuel Sánchez 8 Jul 8, 2022
SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

SharkUtils is a collection of Swift extensions, handy methods and syntactical sugar that we use within our iOS projects at Gymshark.

Gymshark 1 Jul 6, 2021
Recreating a fully functional version of iOS 4 in SwiftUI.

Updates: Version 1.0 is currently available ?? While I work on fixing an issue in Xcode 12.5+ with LazyVGrid, I recommend you build using Xcode 12.4 a

null 2.9k Jan 1, 2023
Helpful extensions for iOS app development 🚀

ExtensionKit includes many extensions, from getting the user location with a deterministic Combine API to a shimmer loading animation, to keyboard notification updates, bottom sheet and much much more. Check out the docs below or install the library with SPM to try it out.

Gary Tokman 110 Oct 31, 2022