Here are 2 functions. One returns [Range<String.Index>], the other returns [Range<Int>]. If you don't need the former, you can make it private. I've designed it to mimic the range(of:options:range:locale:) method, so it supports all the same features.
import Foundation
extension String {
    public func allRanges(
        of aString: String,
        options: String.CompareOptions = [],
        range: Range<String.Index>? = nil,
        locale: Locale? = nil
    ) -> [Range<String.Index>] {
        // the slice within which to search
        let slice = (range == nil) ? self[...] : self[range!]
        var previousEnd = s.startIndex
        var ranges = [Range<String.Index>]()
        while let r = slice.range(
            of: aString, options: options,
            range: previousEnd ..< s.endIndex,
            locale: locale
        ) {
            if previousEnd != self.endIndex { // don't increment past the end
                    previousEnd = self.index(after: r.lowerBound)
            }
            ranges.append(r)
        }
        return ranges
    }
    public func allRanges(
        of aString: String,
        options: String.CompareOptions = [],
        range: Range<String.Index>? = nil,
        locale: Locale? = nil
    ) -> [Range<Int>] {
        return allRanges(of: aString, options: options, range: range, locale: locale)
            .map(indexRangeToIntRange)
    }
    private func indexRangeToIntRange(_ range: Range<String.Index>) -> Range<Int> {
        return indexToInt(range.lowerBound) ..< indexToInt(range.upperBound)
    }
    private func indexToInt(_ index: String.Index) -> Int {
        return self.distance(from: self.startIndex, to: index)
    }
}
let s = "abc abc  abc   abc    abc"
print(s.allRanges(of: "abc") as [Range<String.Index>])
print()
print(s.allRanges(of: "abc") as [Range<Int>])