WKZombie is a Swift framework for iOS/OSX to navigate within websites and collect data without the need of User Interface or API, also known as Headless browser.

Overview

WKZombie

Twitter: @mkoehnke Version Carthage compatible SPM compatible License Platform Build Status

WKZombie is an iOS/OSX web-browser without a graphical user interface. It was developed as an experiment in order to familiarize myself with using functional concepts written in Swift 4.

It incorporates WebKit (WKWebView) for rendering and hpple (libxml2) for parsing the HTML content. In addition, it can take snapshots and has rudimentary support for parsing/decoding JSON elements. Chaining asynchronous actions makes the code compact and easy to use.

Use Cases

There are many use cases for a Headless Browser. Some of them are:

  • Collect data without an API
  • Scraping websites
  • Automating interaction of websites
  • Manipulation of websites
  • Running automated tests / snapshots
  • etc.

Example

The following example is supposed to demonstrate the WKZombie functionality. Let's assume that we want to show all iOS Provisioning Profiles in the Apple Developer Portal.

Manual Web-Browser Navigation

When using a common web-browser (e.g. Mobile Safari) on iOS, you would typically type in your credentials, sign in and navigate (via links) to the Provisioning Profiles section:

Automation with WKZombie

The same navigation process can be reproduced automatically within an iOS/OSX app linking WKZombie Actions. In addition, it is now possible to manipulate or display this data in a native way with UITextfield, UIButton and a UITableView.

Take a look at the iOS/OSX demos in the Example directory to see how to use it.

Getting Started

iOS / OSX

The best way to get started is to look at the sample project. Just run the following commands in your shell and you're good to go:

$ cd Example
$ pod install
$ open Example.xcworkspace

Note: You will need CocoaPods 1.0 beta4 or higher.

Command-Line

For a Command-Line demo, run the following commands inside the WKZombie root folder:

$ swift build -Xcc -I/usr/include/libxml2 -Xlinker -lxml2

$ .build/debug/Example 
    
    

    
   

Usage

A WKZombie instance equates to a web session. Top-level convenience methods like WKZombie.open() use a shared instance, which is configured with the default settings.

As such, the following three statements are equivalent:

let action : Action<HTMLPage> = open(url)
let action : Action<HTMLPage> = WKZombie.open(url)
let browser = WKZombie.sharedInstance
let action : Action<HTMLPage> = browser.open(url)

Applications can also create their own WKZombie instance:

self.browser = WKZombie(name: "Demo")

Be sure to keep browser in a stored property for the time of being used.

a. Chaining Actions

Web page navigation is based on Actions, that can be executed implicitly when chaining actions using the >>> or >>* (for snapshots) operators. All chained actions pass their result to the next action. The === operator then starts the execution of the action chain.

The following snippet demonstrates how you would use WKZombie to collect all Provisioning Profiles from the Developer Portal and take snapshots of every page:

>> setAttribute("value", value: user) >>* get(by: .id("accountpassword")) >>> setAttribute("value", value: password) >>* get(by: .name("form2")) >>> submit >>* get(by: .contains("href", "/account/")) >>> click(then: .wait(2.5)) >>* getAll(by: .contains("class", "row-")) === myOutput ">
    open(url)
>>* get(by: .id("accountname"))
>>> setAttribute("value", value: user)
>>* get(by: .id("accountpassword"))
>>> setAttribute("value", value: password)
>>* get(by: .name("form2"))
>>> submit
>>* get(by: .contains("href", "/account/"))
>>> click(then: .wait(2.5))
>>* getAll(by: .contains("class", "row-"))
=== myOutput

In order to output or process the collected data, one can either use a closure or implement a custom function taking the result as parameter:

func myOutput(result: [HTMLTableColumn]?) {
  // handle result
}

or

func myOutput(result: Result<[HTMLTableColumn]>) {
  switch result {
  case .success(let value): // handle success
  case .error(let error): // handle error
  }
}

b. Manual Actions

Actions can also be started manually by calling the start() method:

let action : Action<HTMLPage> = browser.open(url)

action.start { result in
    switch result {
    case .success(let page): // process page
    case .error(let error):  // handle error
    }
}

This is certainly the less complicated way, but you have to write a lot more code, which might become confusing when you want to execute Actions successively.

Basic Action Functions

There are currently a few Actions implemented, helping you visit and navigate within a website:

Open a Website

The returned WKZombie Action will load and return a HTML or JSON page for the specified URL.

func open<T : Page>(url: URL) -> Action<T>

Optionally, a PostAction can be passed. This is a special wait/validation action, that is performed after the page has finished loading. See PostAction for more information.

func open<T : Page>(then: PostAction) -> (url: URL) -> Action<T>

Get the current Website

The returned WKZombie Action will retrieve the current page.

func inspect<T: Page>() -> Action<T>

Submit a Form

The returned WKZombie Action will submit the specified HTML form.

func submit<T : Page>(form: HTMLForm) -> Action<T>

Optionally, a PostAction can be passed. See PostAction for more information.

func submit<T : Page>(then: PostAction) -> (form: HTMLForm) -> Action<T>

Click a Link / Press a Button

The returned WKZombie Actions will simulate the interaction with a HTML link/button.

func click<T: Page>(link : HTMLLink) -> Action<T>
func press<T: Page>(button : HTMLButton) -> Action<T>

Optionally, a PostAction can be passed. See [PostAction](#Special- Parameters) for more information.

func click<T: Page>(then: PostAction) -> (link : HTMLLink) -> Action<T>
func press<T: Page>(then: PostAction) -> (button : HTMLButton) -> Action<T>

Note: HTMLButton only works if the "onClick" HTML-Attribute is present. If you want to submit a HTML form, you should use Submit instead.

Find HTML Elements

The returned WKZombie Action will search the specified HTML page and return the first element matching the generic HTML element type and passed SearchType.

func get<T: HTMLElement>(by: SearchType<T>) -> (page: HTMLPage) -> Action<T>

The returned WKZombie Action will search and return all elements matching.

func getAll<T: HTMLElement>(by: SearchType<T>) -> (page: HTMLPage) -> Action<[T]>

Set an Attribute

The returned WKZombie Action will set or update an existing attribute/value pair on the specified HTMLElement.

func setAttribute<T: HTMLElement>(key: String, value: String?) -> (element: T) -> Action<HTMLPage>

Execute JavaScript

The returned WKZombie Actions will execute a JavaScript string.

func execute(script: JavaScript) -> (page: HTMLPage) -> Action<JavaScriptResult>
func execute(script: JavaScript) -> Action<JavaScriptResult>

For example, the following example shows how retrieve the title of the currently loaded website using the execute() method:

    browser.inspect
>>> browser.execute("document.title")
=== myOutput

func myOutput(result: JavaScriptResult?) {
  // handle result
}

The following code shows another way to execute JavaScript, that is e.g. value of an attribute:

>> browser.map { $0.objectForKey("onClick")! } >>> browser.execute >>> browser.inspect === myOutput func myOutput(result: HTMLPage?) { // handle result } ">
    browser.open(url)
>>> browser.get(by: .id("div"))
>>> browser.map { $0.objectForKey("onClick")! }
>>> browser.execute
>>> browser.inspect
=== myOutput

func myOutput(result: HTMLPage?) {
  // handle result
}

Fetching

Some HTMLElements, that implement the HTMLFetchable protocol (e.g. HTMLLink or HTMLImage), contain attributes like "src" or "href", that link to remote objects or data. The following method returns a WKZombie Action that can conveniently download this data:

func fetch<T: HTMLFetchable>(fetchable: T) -> Action<T>

Once the fetch method has been executed, the data can be retrieved and converted. The following example shows how to convert data, fetched from a link, into an UIImage:

let image : UIImage? = link.fetchedContent()

Fetched data can be converted into types, that implement the HTMLFetchableContent protocol. The following types are currently supported:

  • UIImage / NSImage
  • Data

Note: See the OSX example for more info on how to use this.

Transform

The returned WKZombie Action will transform a WKZombie object into another object using the specified function f.

func map<T, A>(f: T -> A) -> (element: T) -> Action<A>

This function transforms an object into another object using the specified function f.

func map<T, A>(f: T -> A) -> (object: T) -> A

Taking Snapshots

Taking snapshots is available for iOS. First, a snapshotHandler must be registered, that will be called each time a snapshot has been taken:

WKZombie.sharedInstance.snapshotHandler = { snapshot in
    let image = snapshot.image
}

Secondly, adding the >>* operator will trigger the snapshot event:

    open(url)
>>* get(by: .id("element"))
=== myOutput

Note: This operator only works with the WKZombie shared instance.

Alternatively, one can use the snap command:

    browser.open(url)
>>> browser.snap
>>> browser.get(by: .id("element"))
=== myOutput

Take a look at the iOS example for more information of how to take snapshots.

Special Parameters

1. PostAction

Some Actions, that incorporate a (re-)loading of webpages (e.g. open, submit, etc.), have PostActions available. A PostAction is a wait or validation action, that will be performed after the page has finished loading:

PostAction Description
wait (Seconds) The time in seconds that the action will wait (after the page has been loaded) before returning. This is useful in cases where the page loading has been completed, but some JavaScript/Image loading is still in progress.
validate (Javascript) The action will complete if the specified JavaScript expression/script returns 'true' or a timeout occurs.

2. SearchType

In order to find certain HTML elements within a page, you have to specify a SearchType. The return type of get() and getAll() is generic and determines which tag should be searched for. For instance, the following would return all links with the class book:

let books : Action<HTMLLink> = browser.getAll(by: .class("book"))(page: htmlPage)

The following 6 types are currently available and supported:

SearchType Description
id (String) Returns an element that matches the specified id.
name (String) Returns all elements matching the specified value for their name attribute.
text (String) Returns all elements with inner content, that contain the specified text.
class (String) Returns all elements that match the specified class name.
attribute (String, String) Returns all elements that match the specified attribute name/value combination.
contains (String, String) Returns all elements with an attribute containing the specified value.
XPathQuery (String) Returns all elements that match the specified XPath query.

Operators

The following Operators can be applied to Actions, which makes chained Actions easier to read:

Operator iOS OSX Description
>>> x x This Operator equates to the andThen() method. Here, the left-hand side Action will be started and the result is used as parameter for the right-hand side Action. Note: If the right-hand side Action doesn't take a parameter, the result of the left-hand side Action will be ignored and not passed.
>>* x This is a convenience operator for the snap command. It is equal to the >>> operator with the difference that a snapshot will be taken after the left Action has been finished. Note: This operator throws an assert if used with any other than the shared instance.
=== x x This Operator starts the left-hand side Action and passes the result as Optional to the function on the right-hand side.

Authentication

Once in a while you might need to handle authentication challenges e.g. Basic Authentication or Self-signed Certificates. WKZombie provides an authenticationHandler, which is invoked when the internal web view needs to respond to an authentication challenge.

Basic Authentication

The following example shows how Basic Authentication could be handled:

browser.authenticationHandler = { (challenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) in
	return (.useCredential, URLCredential(user: "user", password: "passwd", persistence: .forSession))
}

Self-signed Certificates

In case of a self-signed certificate, you could use the authentication handler like this:

browser.authenticationHandler = { (challenge) -> (URLSession.AuthChallengeDisposition, URLCredential?) in
	return (.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}

Advanced Action Functions

Batch

The returned WKZombie Action will make a bulk execution of the specified action function f with the provided input elements. Once all actions have finished executing, the collected results will be returned.

func batch<T, U>(f: T -> Action<U>) -> (elements: [T]) -> Action<[U]>

Collect

The returned WKZombie Action will execute the specified action (with the result of the previous action execution as input parameter) until a certain condition is met. Afterwards, it will return the collected action results.

func collect<T>(f: T -> Action<T>, until: T -> Bool) -> (initial: T) -> Action<[T]>

Swap

Note: Due to a XPath limitation, WKZombie can't access elements within an iframe directly. The swap function can workaround this issue by switching web contexts.

The returned WKZombie Action will swap the current page context with the context of an embedded

Comments
  • HTTPS request unable to parse

    HTTPS request unable to parse

    Cancelling Rendering - Optional("REQUEST\nhttps://192.168.0.1:12380/") .2016-10-26 21:09:43.529 DYC[12587:442455] Unable to parse.

    I can give you an external address to this if you need it, it is using a self sign cert just wondering how to get round this

    opened by avisual 6
  • Get all HTMLRows in HTMLTable on page

    Get all HTMLRows in HTMLTable on page

    Hi,

    I'm trying to convert my backend scraper to an on-device scraper using your library, but I'm finding it hard to understand the documentation without examples, how would one use WKZombie to login and get a HTML Table, and how do you debug it? I can't seem to get document.title to print anything other than nil. I'm opening an URL that will redirect me to a page, where I can login.

    I have the following code for now:

    func testScraper(_ url: URL, user: String, password: String) {
        open(url)
            >>> get(by: .id("username"))
            >>> setAttribute("value", value: user)
            >>> get(by: .id("password"))
            >>> setAttribute("value", value: password)
            >>> get(by: .name("f"))
            >>> submit(then: .wait(2.0))
            >>> getAll(by: .contains("class", "DataSelect"))
            === handleResult
    }
    

    But I'm just getting a "error loading page: Not found" when printing the result, but I can't debug it without knowing if it has been redirected before It tries to get the table and forth? And do you recommend using browser.* instead of the >>> operators? I'm having a very difficult time adjusting the example code to my own use-case, as I keep getting errors like "operands here have types 'Action' and '([HTMLElement]) -> ()'.

    All the best, Christian

    opened by CaptainMack 6
  • UI API called on a background thread - iOS 11 - Xcode 9

    UI API called on a background thread - iOS 11 - Xcode 9

    Hi! FYI: WKZombie unfortunately does not work on iOS 11. The NSOperationQueue is of type USER_INITIATED and calls to WKWebView requires to be on the main thread.

    With the new Main Thread Checker in XCode 9 it prints out the following in the console:

    • Main Thread Checker: UI API called on a background thread: -[WKWebView isLoading]
    • Main Thread Checker: UI API called on a background thread: -[WKWebView configuration]
    • Main Thread Checker: UI API called on a background thread: -[WKUserContentController addScriptMessageHandler:name:]
    • Main Thread Checker: UI API called on a background thread: -[WKWebView setNavigationDelegate:]
    • Main Thread Checker: UI API called on a background thread: -[WKWebView loadRequest:]
    • Main Thread Checker: UI API called on a background thread: -[WKWebView evaluateJavaScript:completionHandler:]

    Best regards, Erik

    opened by fishfisher 5
  • open method not visible when using WKZombie in Objective C project

    open method not visible when using WKZombie in Objective C project

    Hi, after adding WKZombie to my podfile and adding @import WKZombie;, I can invoke some methods on the WKZombie.shareInstance, e.g. dump, setTimeoutSeconds, but the essential open method is not visible for some reasons.

    Would you have any hints on how to solve this?

    thanks.

    opened by billylo1 5
  • click() assumes links?

    click() assumes links?

    I have an use case where I need to click a <button> on the page. I tried using >>> click(), but It looks like that action assumes the target to be an <a> tag. How can I use WKZombie to click a button on the webpage?

    opened by insidegui 5
  • Swift Package Manager - unsupported layout

    Swift Package Manager - unsupported layout

    Hi I am receiving the following whenever I try to download using SPM.

    error: the package has an unsupported layout, unexpected source file(s) found: /Users/Reid/Developer/airbnb_wishlister/Packages/WKZombie-1.0.6/Tests/Tests.swift fix: move the file(s) inside a module

    opened by rchatham 4
  • Form submission

    Form submission

    Hello, is it possible to submit a form without the form's name or just with the id?

    I tried doing: browser.get(by: .Id("theId") ) or browser.get(by: .Name(""))

    browser.submit ()

    and the browser.dump just returns ... after it returns the html of the page.

    Sorry for having too many questions and thanks in advance!

    bug 
    opened by jaloo555 4
  • === problem

    === problem

    Hi, I tried using WKZombie for this code

    browser.open(url)

    browser.get(by: .Id("Username")) browser.setAttribute("value", value: username) browser.get(by: .Id("Password")) browser.setAttribute("value", value: password) browser.get(by: .Id("site-login-form")) browser.submit(then: .Wait(2.0)) browser.get(by: .Contains("href", "#studentmyday/schedule")) browser.click(then: .Wait(2.0)) browser.getAll(by: .Id("accordionSchedules")) === handleResult

    and it returns the error: Binary operator '===' cannot be applied to operands of type 'Action<[HTMLElement]>' (aka 'Action<Array>') and '(Action<[HTMLTableRow]>) -> ()'

    . All the methods are the same with the sample files and I am sure I have the update version. Any ideas? Thanks!

    opened by jaloo555 4
  • Update to Swift 3?

    Update to Swift 3?

    This framework looks perfect for what I've been looking for! The only problem is that my app is made in Swift 3, and yours seems to be older than that. I installed the Cocoapod, and there were 99 errors! The reason is because it needs to be updated. So is there an update to WKZombie for Swift 3 comming anytime soon?

    opened by odonckers 3
  • Show network activity indicator

    Show network activity indicator

    When WKZombie is loading a webpage or fetching content online, it would be good to show network activity indicator on the status bar by internally increasing and decreasing network activity count.

    Or, WKZombie can send notifications to allow users handle network activity indicator themselves.

    enhancement 
    opened by gbmksquare 3
  • Migrated to Swift 5.2 and added protocol fix for XCode 12

    Migrated to Swift 5.2 and added protocol fix for XCode 12

    Some minor updates to fix for Xcode 12 (the current version won't build as it complains about type T not having an init method in Parser.swift - adding a simple Initializable protocol with the required init method fixes it). And some updates to bring the code from Swift 4 to Swift 5.2 and remove the constant warnings to migrate it.

    opened by maxesse 1
  • Not opening forms and href as relative?

    Not opening forms and href as relative?

    When i submit a form or try to open a href, i get network request failure As i think its trying to open the action without the baseurl? for example:

    <form action="/some/action">
    

    where the url is relative not absolute.

    Is this intentional? And is there a workaround?

    Thanks

    opened by nicwhitts 0
  • Trying to import swift.package

    Trying to import swift.package

    So im trying to import the swift package, just to get the darn thing to start but i keep getting this error when ever i try to add package dependency: The package dependency graph can not be resolved; unable find any available tag for the following requirements:

    Even if I have the Package.Swift in xcode I cant import Package becasue ill get hit with the

    /Users/Stjames/Desktop/Instore/Package.swift:1:8: No such module 'PackageDescription'

    Im having alot of trouble even getting started :(

    any help would be great

    opened by Stjames19 0
  • Help me with the error caused by === syntax with Xcode 11.1

    Help me with the error caused by === syntax with Xcode 11.1

    I am using the Xcode version 11.1 targeting ios 12.0 image

    I have just installed this framework pretending to make some automatization process with this framework on the native ios web browser. But I find this error at the beginning and I have no idea why. Can anyone help me to continue?

    opened by jiaxiangcheng 1
  • Help with OpenThen, Batch, Fetch Functions

    Help with OpenThen, Batch, Fetch Functions

    Hi @mkoehnke!

    Thank You: First, thank you for building this repo, I've only been able to use some of the basic features, but it's already been incredibly useful!

    Goal: I'm using WKZombie to open a website, login, wait for redirect, scrape video links, scrape each video source, and download the linked files. The video source is on the individual page of each video link.

    Problems:

    • Signing into social networks like LinkedIn.
    • Performing many URL Requests at once causes the host to block access.

    Request: Could you please help teach how to login to LinkedIn, delay URL requests, and use openThen?

    Additional Notes:

    • Read WKZombie manual, reviewed iOS and MacOS demo, reviewed swift files in WKZombie pod, and searched Stack Overflow, Google, YouTube, and GitHub for examples.
    • Using WKZombie with SwiftSoup.
    opened by david-littlefield 0
Releases(1.1.1)
  • 1.1.1(Mar 3, 2018)

  • 1.1.0(Sep 23, 2017)

    This release brings iOS11 + Swift 4 compability and includes:

    • Fixes issues raised by Xcode's Main Thread Checker
    • Documentation of how to use Alamofire and WKZombie in the same project
    Source code(tar.gz)
    Source code(zip)
  • 1.0.8(Mar 3, 2017)

    This version adds the showNetworkActivity property, that can be used to enable/disable the network activity indicator in the status bar. Furthermore, there's better error handling in the iOS sample.

    Source code(tar.gz)
    Source code(zip)
  • 1.0.7(Feb 9, 2017)

  • 1.0.6(Dec 18, 2016)

    This version adds an authentication handler to the WKZombie class, which can be used to handle authentication challenges (e.g. Basic Authentication).

    Source code(tar.gz)
    Source code(zip)
  • 1.0.5(Sep 20, 2016)

    This version adds support for building WKZombie with the Swift Package Manager. As iOS targets are currently not supported, this feature is OSX only.

    To build a module, use the following command inside the WKZombie root folder:

    swift build -Xcc -I/usr/include/libxml2 -Xlinker -lxml2
    
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Sep 19, 2016)

    This release requires Xcode 8.0 because it has been completely refactored to compile against Swift 3.0. Any older versions of Xcode will NOT COMPILE.

    Source code(tar.gz)
    Source code(zip)
  • 0.9.5(Jun 20, 2016)

    • Due to a XPath limitation, WKZombie can't access elements within an iFrame directly. In order to work around this issue, a swap() method was added to switch the current page with an embedded iframe page.
    • Bugfix for submitting a form using the ID tag
    • Added additonal execute() / map() functions for easier JavaScript usage
    • Breaking Change: Removed brackets from execute() and snap() function
    Source code(tar.gz)
    Source code(zip)
  • 0.9.4(May 26, 2016)

    • Added support for taking snapshots (#31)
    • Added property for setting/getting the user agent
    • === operator now accepts functions/closures with Result and Optionals as parameter
    Source code(tar.gz)
    Source code(zip)
  • 0.9.3(Apr 10, 2016)

    WKZombie 0.9.3 is a small release, but with several worthwhile and important improvements:

    • Carthage support
    • Added ability to set a process pool for each WKZombie instance (thanks @insidegui)
    • New JavaScript execute() method
    • New inspect() method for retrieving the currently loaded page
    • Added HTMLButton class + press() method to "click" a
    • Added Logger class to enable/disable WKZombie logging
    Source code(tar.gz)
    Source code(zip)
Owner
Mathias Köhnke
Mathias Köhnke
An RSS, Atom and JSON Feed parser written in Swift

Features Atom RSS 0.90, 0.91, 1.00, 2.00 JSON Namespaces Dublin Core Syndication Content Media RSS iTunes Podcasting Tags Documentation Unit Test Cove

Nuno Dias 1k Jan 7, 2023
AcknowledgementsPlist manages the licenses of libraries that depend on your iOS app.

What's AcknowledgementsPlist AcknowledgementsPlist that combines licenses of Carthage, CocoaPods, and Manual Plist into Bundle and Plist. I implement

CATS Open Source Softwares 75 Nov 3, 2022
Swift wrappers for the tree-sitter incremental parsing system

SwiftTreeSitter Swift wrappers for the tree-sitter incremental parsing system. Remember that tree-sitter has both runtime and per-language dependencie

Chime 153 Dec 8, 2022
A Powerful , Extensible CSS Parser written in pure Swift.

A Powerful , Extensible CSS Parser written in pure Swift. Basic Usage From CSS: #View { "width" : 118; "height" : 120.5; "color1" : "#888888"; "co

null 273 Sep 9, 2022
Recursive Length Prefix encoding written in Swift

RLPSwift This is a basic Swift implementation of Recursive Length Prefix Encoding, a serialisation method for encoding arbitrarily structured binary d

bitfwd community 22 Oct 6, 2020
Excel spreadsheet (XLSX) format parser written in pure Swift

CoreXLSX Excel spreadsheet (XLSX) format parser written in pure Swift CoreXLSX is a library focused on representing the low-level structure of the XML

null 684 Dec 21, 2022
WKZombie is a Swift framework for iOS/OSX to navigate within websites and collect data without the need of User Interface or API, also known as Headless browser.

WKZombie WKZombie is an iOS/OSX web-browser without a graphical user interface. It was developed as an experiment in order to familiarize myself with

Mathias Köhnke 1.1k Dec 16, 2022
WKZombie is an iOS/OSX web-browser without a graphical user interface.

WKZombie is a Swift framework for iOS/OSX to navigate within websites and collect data without the need of User Interface or API, also known as Headless browser. It can be used to run automated tests / snapshots and manipulate websites using Javascript.

Mathias Köhnke 1.1k Dec 16, 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
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
WebKit aims to provide platform agnostic isolated browser environments without the need for sketchy C bindings or a bloated V8 runtime.

WebKit WebKit aims to provide platform agnostic isolated browser environments without the need for sketchy C bindings or a bloated V8 runtime. Running

Linden 1 Nov 26, 2021
A fast, convenient and nonintrusive conversion framework between JSON and model. Your model class doesn't need to extend any base class. You don't need to modify any model file.

MJExtension A fast, convenient and nonintrusive conversion framework between JSON and model. 转换速度快、使用简单方便的字典转模型框架 ?? ✍??Release Notes: more details Co

M了个J 8.5k Jan 3, 2023
SwiftUI implementation of Conway’s Game of Life — also known as “Life”.

Life Conway’s Game of Life SwiftUI implementation of Conway’s Game of Life — also known simply as “Life”. About I’m Martin, an indie dev from Berlin.

Martin Lexow 23 Jan 21, 2022
SwiftUI package to present a Bottom Sheet interactable view with the desired Detents. Also known as Half sheet.

BottomSheetSUI BottomSheetSUI is a package that gives you the ability to show a Bottom sheet intractable, where you can add your own SwiftUI view. You

Aitor Pagán 8 Nov 28, 2022
A drop-in universal library allows to record audio within the app with a nice User Interface.

IQAudioRecorderController IQAudioRecorderController is a drop-in universal library allows to record and crop audio within the app with a nice User Int

Mohd Iftekhar Qurashi 637 Nov 17, 2022
Pick a date and explore websites from the early days of the internet to now all in an easy-to-use browser format! 💻

Pick a date and explore websites from the early days of the internet to now all in an easy-to-use browser format! ??

Liam 5 Nov 26, 2022
SwiftWebKit - This app look like a browser, but you can navigate between 2 sites

import UIKit import WebKit My first app for WebKit. This app look like a browser

Ahmet Onur Şahin 3 Apr 18, 2022
CryptoWatch is an application to fetch the currency datas from an api and show their updated values to user. User is able to get the coin datas without an extra effort.

CryptoTracker In order to combine my work and studies, I made a small project that keeps the user's registration datas in memory, checks them when nee

Ömer Faruk Kılıçaslan 2 Jun 27, 2022
The iOS pod which can collect profile data to detect code coverage.

CodeCoverageKit Installation CodeCoverageKit is available through CocoaPods.

木子 2 Sep 29, 2021
Library that makes it easy to create multiple environments within a single app. You can switch environments without deleting the application.

AppContainer Library that makes it easy to create multiple environments within a single app. You can switch environments without deleting the applicat

null 8 Dec 15, 2022