DEV Community

Cover image for [SwiftUI] How I Built OSS News App
Fumiya Yamanaka
Fumiya Yamanaka

Posted on

[SwiftUI] How I Built OSS News App

This post is originally published in Japanese a half years ago. I want someone to know how create an iOS app with modern technology and how I struggled with that. Please enjoy!!


I built an OSS news app for iOS with SwiftUI.
Please give me stars on GitHub!

GitHub logo mtfum / NewsUI

Simple news iOS app with SwiftUI

NewsUI

Simple news iOS app with SwiftUI 🗞️ which uses NewsAPI to fetch top news headlines

The codebase uses following modern keys:

  • SwiftUI
  • Async/Await
  • Swift Package Manager

Features

  • Get Headlines
  • Search News

Requirements

  • Xcode13+
  • iOS 15+

Getting started

  • git clone https://github.com/mtfum/NewsUI
  • cd NewsUI
  • insert YOUR_NEWS_API_KEY in NewsClient.swift, you can get from https://newsapi.org/
  • Build SwiftUIApp
  • Enjoy! 🎉

Libraries

Architecture

Architecture




GitHub logo mtfum / NewsAPI

An unofficial supported Swift client library for accessing News API.

NewsAPI

An API framework for newsapi.org with Swift.

Requirement

  • Swift5.5+

Installation

Swift Package Manager

.package(url: "https://github.com/mtfum/NewsAPI.git", from: "0.1.0")
Enter fullscreen mode Exit fullscreen mode

Usage

Setup

import NewsAPI

let client = NewsAPI(apiKey: "YOUR_API_KEY")
Enter fullscreen mode Exit fullscreen mode

Get Sources

let articles = try await client.getSources(
    sources: [String] = [], // abc-news, bbc-news, etc...
    query: String? = nil,
    category: NewsSourceCategory? = nil,
    language: Language = Language.en
)
Enter fullscreen mode Exit fullscreen mode

Search

let articles = try await client.search(
  query: "",
  sources: [String] = [],
  sortBy: SortBy? = nil, // relevancy, popularity, publishedAt
  language: Language? = nil
)
Enter fullscreen mode Exit fullscreen mode

Top-Headlines

let articles = try await client.getTopHeadlines(
  category: NewsSourceCategory? = nil,
  language
Enter fullscreen mode Exit fullscreen mode

Why I built this

Apple had released a lot of new API in WWDC 2021. Everything is very exciting and motivated me to create a new app though, I just wanted to experiment the new feature like Searchable and Refreshable or new feature of Swift language like Concurrency.

Therefore, the app itself requires Xcode 13 or higher and iOS 15 or higher.

About App

This app uses the newsapi.org API to search for the world's top news and specific words.
It consists of three tabs and implements only the minimum necessary functions.
I'm personally satisfied with it because it accomplished the purpose of trying out the new features I mentioned above.

Headline Search Publishers
Screenshot for Headline Screenshot for Search Screenshot for Publishers

NewsAPI: Concurrency

With the creation of the app, I wrapped the API of newsapi.org and released it as an iOS library.
I could have left it as an internal implementation, but I cut it out as a library for the following reasons.

  • There was no Swift library for newsapi that supported asynchronous processing.
  • I want people who want to make iOS apps to use it.
  • I wanted to do it as a part of OSS activity.

From here, I will lightly introduce the API that uses async/await syntax, the most significant language feature added in Swift 5.5.
The following is a sample code that uses the NewsAPI to get the headline news.

func getHeadlines() async -> [NewsArticle] {
  do {
    let articles = try await NewsAPI(apiKey: "YOUR_API_KEY").getTopHeadlines()
    return articles
  } catch {
    // do something
  }
}
Enter fullscreen mode Exit fullscreen mode

If you read the above code, you will see that instead of using traditional closures, the keyword async is added to the method and the keyword await is used inside.
This method, getHeadlines, is defined as an asynchronous function, so it needs the await keyword right before it.
Since await suspends the process immediately after it is written, it is more intuitive to write.
Not only does it improve readability by reducing the number of lines of code and the depth of nesting, but it also expands the scope of expression by allowing multiple asynchronous processes to be handled simultaneously.

NewsUI: App Architecture

Here is an explanation of the application itself.
The following image shows an easy-to-understand diagram of the app structure.

NewsUI App Architecture

As mentioned in the above section, NewsAPI (red part) has been cut out as an external library.
Only the internal NewsClient depends on the NewsAPI, and each feature depends on it.
All the features in the yellow part of the image are managed as Packages, and the Package.json file is structured as follows.

// https://github.com/mtfum/NewsUI/blob/main/Package.swift

import PackageDescription

let package = Package(
  name: "NewsUI",
  platforms: [
    .iOS("15.0")
  ],
  products: [
    .library(name: "AppFeature", targets: ["AppFeature"]),
    .library(name: "SearchFeature", targets: ["SearchFeature"]),
    .library(name: "HeadlinesFeature", targets: ["HeadlinesFeature"]),
    .library(name: "SourcesFeature", targets: ["SourcesFeature"])
  ],
  dependencies: [
    .package(url: "https://github.com/mtfum/NewsAPI.git", from: "0.1.0"),
    .package(url: "https://github.com/apple/swift-collections.git", from: "0.0.1"),
  ],
  targets: [
    .target(name: "AppComponent", dependencies: ["NewsAPI"]),
    .target(name: "AppFeature", dependencies: ["SearchFeature", "HeadlinesFeature", "SourcesFeature"]),
    .target(name: "NewsClient", dependencies: ["NewsAPI"]),
    .target(name: "SearchFeature", dependencies: ["AppComponent", "NewsClient", .product(name: "OrderedCollections", package: "swift-collections")]),
    .target(name: "HeadlinesFeature", dependencies: ["AppComponent", "NewsClient"]),
    .target(name: "SourcesFeature", dependencies: ["AppComponent", "NewsClient"])
  ]
)
Enter fullscreen mode Exit fullscreen mode

The app is divided into multiple modules, and each module is divided into different functions (in this case, tabs) so that they cannot be cross-referenced.
Multi-module system has some merits such as clear dependencies and optimized compilation, but for a small app like this one, you won't get much benefit from it.


Though it is an unnecessary addition, we call it Hyper-modularization, and isowords is being developed with 86 modules.

GitHub logo pointfreeco / isowords

Open source game built in SwiftUI and the Composable Architecture.

isowords

CI

This repo contains the full source code for isowords, an iOS word search game played on a vanishing cube. Connect touching letters to form words, the longer the better, and the third time a letter is used its cube is removed, revealing more letters inside!

Available on the App Store now!

Download isowords on the App Store

isowords screenshots


About

isowords is a large, complex application built entirely in Swift. The iOS client's logic is built in the Composable Architecture and the UI is built mostly in SwiftUI with a little bit in SceneKit. The server is also built in Swift using our experimental web server libraries.

We published a 4-part series of videos covering these topics and more on Point-Free, a video series exploring functional programming and the Swift language, hosted by Brandon Williams and Stephen Celis.


video poster image

Some things you might find interesting:

The Composable


In addition, each feature was integrated into the AppFeature, and the app itself could be simply configured to refer to the AppFeature.

import SwiftUI
import AppFeature

@main
struct NewsUIApp: App {
  var body: some Scene {
    WindowGroup {
      AppFeatureView()
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Wrap-up

This is a brief introduction to NewsUI and NewsAPI, which I have been working on.
I'm happy to publish it now that I have a breakthrough for now.
Please star if you find it helpful!
Thank you for reading.

Top comments (1)

Collapse
 
abdullahth profile image
Abdullah Althobetey

Thanks for sharing