Code Monkey home page Code Monkey logo

ios-base's Introduction

Maintainability Test Coverage License

iOS Base Template

iOS base is a boilerplate project created by Rootstrap for new projects using Swift 5. The main objective is helping any new projects jump start into feature development by providing a handful of functionalities.

Features

This template comes with:

Main

  • Extensible and decoupled integration with an API Client to easily communicate with REST services.
  • A few examples to comprehend the app architecture(e.g. Account creation, Login, Logout)
  • Useful classes to manage User and Session data.
  • Secure way to store and manage secret keys of your third party integrations.
  • Centralized and intuitive navigation system that simplifies the transitioning between view controllers and streamlines the navigation flow within the app.
  • Convenient helpers and extensions to boost your productivity and improve the general coding experience.

How to use

  1. Clone the repo.
  2. Run ./init from the recently created folder.
  3. Initialize a new git repo and add your remote URL.
  4. Done!

To manage user and session persistence after the original sign in/up we store that information in the native UserDefaults. The parameters that we save are due to the usage of Devise Token Auth for authentication on the server side. Suffice to say that this can be modified to be on par with the server authentication of your choice.

Dependencies

Main

  • Alamofire for easy and elegant connection with an API.
  • IQKeyboardManagerSwift for auto-scrolling to current input in long views. Note: this pod is not fully working on iOS 11. Here is the issue we encountered and the meantime solution.
  • Firebase for tools to help you build, grow and monetize your app.

Utilities

We have developed other libraries that can be helpful and you could integrate with the dependency manager of your choice.

  • PagedLists: Custom UITableView and UICollectionView classes to easily handle pagination.
  • RSFontSizes: allows you to manage different font sizes for every device screen size in a flexible manner.
  • RSFormView: a library that helps you to build fully customizable forms for data entry in a few minutes.
  • SwiftGradients: Useful extensions for UIViews and CALayer classes to add beautiful color gradients.

Testing

Mandatory configuration

Firebase

In order for the project to run, you have to follow these steps:

  1. Register your app with Firebase.
  2. Download Firebase configuration file GoogleService-Info.plist from your account.
  3. Add the downloaded file to the /Resources folder.
  4. Done :)

See the Firebase documentation for more information.

Code Quality Standards

In order to meet the required code quality standards, this project runs SwiftLint during the build phase and reports warnings/errors directly through XCode.

NOTE: It's needed to install SwiftLint into your local machine to report warnings/errors.

The current SwiftLint rule configuration is based on Rootstrap's Swift style guides and is synced with the CodeCliemate's configuration file.

NOTE: Make sure you have SwiftLint version 0.35.0 or greater installed to avoid known false-positives with some of the rules.

Security recommendations

Secrets management

We strongly recommend that all private keys be added to a secrets.xcconfig file that will remain locally and not be committed to your project repo.

Adding new secrets

  1. Add the new environment variable in your system:
    • Optional: For local development, you can run export KEY=value in the terminal. Or you could start with a pre-filled secrets.dev.xcconfig file.
    • In your CI/CD platform, simply add the environment variable with its value to the respective settings section.
  2. Add the new key name to the keys.env file. This could be any other file you use as source for the script mentioned in the next step.
  3. Configure your CI/CD to run:
    • chmod u+x setup-env.sh
    • ./setup-env.sh
  4. Add the key to the Info.plist of your app's target. Example: ThirdPartyKey = ${THIRD_PARTY_KEY}
  5. Add a new case to the Secret.Key enum. The rawValue must match the key in the Info.plist file
  6. Use it wisely :)

Note: The setup-env script will fill in the secrets.xcconfig for Staging and Release builds. Use secrets.dev.xcconfig for the Debug Build Configuration.

Secure storage

We recommend using AWS S3 for storing .xcconfig files containing all secrets, as well as any other sensitive files. Alternatively when not using Fastlane Match (eg might not be compatible with some CICD systems), AWS S3 can also be used for storing Certificates, Private Keys and Profiles required for app signing. The CICD code examples (described below) make use of the AWS CLI to download any files relevant for our project from a predefined bucket and folder

Another alternative for managing sensitive files whithin the repo using Git-Secret can be found in the feature/git-secret branch

CI/CD configuration with Bitrise (updated on Dec 12th 2021)

We are going to start using a tool called Bitrise to configure de CI/CD pipelines for mobiles apps.

--> For iOS apps you can find how to do it in this link: https://www.notion.so/rootstrap/iOS-CI-CD-01e00409a0144f5b85212bf889c627dd

Automated Build and Deployment using Fastlane (DEPRECATED)

We use Fastlane to automate code signing, building and release to TestFlight.

See details in Fastlane folder.

Continuous Integration / Delivery (DEPRECATED)

We recommend GitHub Actions for integrating Fastlane into a CI/CD pipeline. You can find two workflows in the GitHub workflows folder:

  • ci.yml : triggered on any push and PR, runs unit tests, coverage report and static analysis with CodeClimate
  • release.yml : triggered on push to specific branches, builds, signs and submits to TestFlight

Alternatively you can merge branch feature/jenkins for some equivalent CICD boilerplate with Jenkins.

On both alternatives we assume usage of Fastlane match for managing signing Certificates and Profiles, and AWS S3 for storing other files containing third-party keys

License

iOS-Base is available under the MIT license. See the LICENSE file for more info.

NOTE: Remove the free LICENSE file for private projects or replace it with the corresponding license.

Credits

iOS Base is maintained by Rootstrap with the help of our contributors.

ios-base's People

Contributors

aguscha333 avatar camilamoscatelli avatar danialepaco avatar diego0510 avatar fabkremer avatar fernandatoledo avatar fltravieso avatar germanstabile avatar glm4 avatar guillepijuan avatar kstoletniy avatar leandrohiga avatar letofranco avatar mariiio avatar mato2593 avatar mcousillas6 avatar mjurfest avatar pmalvasio avatar sebalopez avatar toptierlabs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ios-base's Issues

Refactor APIClient to use Decodable objects or any other generic approach

Currently, the APIClient class tries to parse a dictionary using JSONSerialization, this brings a couple of problems:

  1. single elements or Arrays from a JSON response are not be supported.
  2. The dictionary is then used to convert it into a Data object to then use a JSONDecoder. This is an unnecessary back and forth which adds complexity and more prone to errors.

Ideally, the client would pass a type that would like to get back and the APIClient will handle the rest. An alternativeis to ahve like a middle layer that takes care of the parsing/decoding.

Add automatic logout when devise token expires

Once the devise token expires in the backend, the ios app should be automatically logged out.

Right now when the token expires, the app gets stuck as the session doesn't close and the user is not able to do any action (including logout)

Retry a request in Moya with RxSwift?

I am pretty new to RxSwift and I am using the code from the branch mvvm+rxSwift, which has the following function for a request of given ProviderType -

    open func request<T>(for target: ProviderType,
                         at keyPath: String? = nil
                         ) -> Observable<(T, Response)> where T: Codable {
        return provider.rx.request(target)
        .filterSuccessfulStatusCodes()
        .flatMap { [weak self] response in
          let decodedValue = try response.map(T.self,
                                              atKeyPath: keyPath,
                                              using: self?.jsonDecoder ?? JSONDecoder(),
                                              failsOnEmptyData: true)
          return .just((decodedValue, response))
        }
        .asObservable()
        .catchError { [weak self] error in
          guard let self = self else {
            return Observable.error(error)
          }
          return Observable.error(self.handleError(with: error))
        }
    }

This works pretty well, but now I want to retry the request when the request fails with a status code of 401, after fetching the refresh token. I found this comment on a GitHub issue which tells how it can be achieved but I am still confused how it will work in my case (the comment does not provide context related to how the refresh token mechanism works).

Redirection when login fails

When the login fails (user or password are not ok) the server answer is 401.
In the CommunicationManager if the answer is 401, then the app logs out the user, so the login screen is dismissed and the user go back to the landing screen. Then the error message appears in the landing screen instad of the login screen.

Prepare code for public release

Use rails example for reference.

Include extra branches in documentation.

This guide is very helpful. Thanks to @MaicolBen ๐Ÿ˜€
Open source recommendations:

  • Licence
  • Readme contents: Description, Features/Contents, Getting started, How to use it, Rootstrap Credits
  • Changelog and versioning
  • Blocked main branch for force push
  • CI and code quality configured (with badges)

Change current MVC pattern to MVVM.

Part of Milestone #1

A first set of changes need to be implemented in order to start using MVVM. This will include:

  • Refactor current examples(Sign In, Sign up, etc).
  • Possible changes in the networking services classes.

Next, a FlowManager/Router, Services Providers, Validators can be implemented to complete the goal.

Localization strings should have comments for translators.

  • Ideal: we should have translator comments in the Base language file, as all others should be generated by translators.
  • Better: Have an automatic way to generate Base.strings file from original localizations file(say .yml, .json, etc)

Command PhaseScriptExecution failed with a nonzero exit code

PhaseScriptExecution R.swift

..../AwesomeProject/Build/Intermediates.noindex/AwesomeProject.build/Debug-iphonesimulator/AwesomeProject.build/Script-FE06840022CE7D8300C6294F.sh: line 3: /R.swift/rswift: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code

Xcode 11 beta 5

Update or Remove Facebook SDK

The current version of the Facebook SDK is using UIWebView which is deprecated and not accepted any longer in iTunesConnect/AppStore sumbissions.

Random fails in tests

The testAccountCreation test fails randomly.

Some failure examples:

1:

testAccountCreation, Asynchronous wait failed: Exceeded timeout of 10 seconds, with unfulfilled expectations: "Expect predicate `exists == 1` for object "GetMyProfileButton" Button".

2:

testAccountCreation, Asynchronous wait failed: Exceeded timeout of 10 seconds, with unfulfilled expectations: "Expect predicate `exists == 1` for object "GetMyProfileButton" Button".
  XCTestCaseExtension.swift:16

  testAccountCreation, Failed to get matching snapshot: No matches found for Elements matching predicate '"GetMyProfileButton" IN identifiers' from input {(

Handle navigation in Views instead of ViewModels

IMO App navigation and routing should be in the View part of MVVM, not in the ViewModel.

Two different views might want to continue to different screens after the same View Model does something.

UIStoryboard extension

Add extension to instantiate controllers using generics

extension UIStoryboard {

    public class func instantiateViewController <T: UIViewController>(_ type: T.Type, storyboardIdentifier: String = "Main") -> T? {
        let storyboard = UIStoryboard(name: storyboardIdentifier, bundle: nil)
        return storyboard.instantiateViewController(type)
    }

    public func instantiateViewController <T: UIViewController>(_ type: T.Type) -> T? {
        return instantiateViewController(withIdentifier: String(describing: type)) as? T
    }
}

Decode user

In the decode method (required init(coder aDecoder: NSCoder)) of the user model, the following line should be: self.id = aDecoder.decodeInteger(forKey: "user-id") instead of self.id = aDecoder.decodeObject(forKey: "user-id")

Mechanism to install different schemes at the same time

Usually apps tend to have multiple schemes/build configurations, like Ad-Hoc, Debug and Production.
The current project uses the same bundle ID, so the app would rewrite itself after every installation/run.
It would be nice to have the ability to install several versions of the app based on the existing schemes/build configurations.

Add SwiftLint as pod dependency

We have had issues with Xcode not showing warnings depending on the installation method, adding it as a dependency may solve this issues.

Implement base64 encoding for media sending.

Make ComunicationManager support base64 encoding for images only.
Note: DO NOT delete the current multipart implementation, the swift-base must allow the user to decide the encoding to every Media.

Force update feature

At some point, any app may need force update to run correctly. It's nice to have this from day 1 implemented just in case. Maybe as a separated branch as an optional feature but I think would be nice to have it.

Close session if 401 forbidden is returned from API.

While using tokens from device_token_auth for session management, implement feature to invalidate the current session if error code 401 is returned in any request.
That way, when the token expires the user is not longer stuck with an invalid session.

add .patch case to JSONEncoding.default in APIClient

Great repo ๐Ÿ˜„!! Attempted to push a branch and PR but got 'denied access' ๐Ÿค•. would love to contribute! Took me a while to figure out why my server wasn't processing the request correctly but found out that patch wasn't using JSON encoding at default ๐Ÿ˜‰

one liner in my attempted PR:

class func defaultEncoding(forMethod method: HTTPMethod) -> ParameterEncoding {
    switch method {
    case .post, .put:
      return JSONEncoding.default
    default:
      return URLEncoding.default
    }
  }

to

class func defaultEncoding(forMethod method: HTTPMethod) -> ParameterEncoding {
    switch method {
    case .post, .put, .patch:
      return JSONEncoding.default
    default:
      return URLEncoding.default
    }
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.