Скрыть файлы .json при включении в Cocoa Touch Framework

Я хотел бы выделить cocoa touch framework, включая некоторые json файлы, которые содержат логику, которую я не хочу видеть пользователю фреймворка; к сожалению, внутри файла .framework все еще отображается json.

Я подумал о том, чтобы включить его в быстрый файл:

struct JsonProvider {
    static let json = "..."
}

но мой json настолько велик, что файл больше не используется. Я не нашел решение для компиляции командной строки, а затем включил его.

Есть ли решение одной из двух задач, т.е.

  • скрыть json внутри рамки или
  • предварительно скомпилировать быстрый файл и затем добавить его в фреймворк?

Ответ 1

Итак, я создал структуру JSONEncoder следующим образом:

public struct JSONEncoder {

  private static var JSON = ""
  public static var JSONData = [UInt8]()
  private static var cipher = [UInt8]()
  public static var encryptedJSONData = [UInt8]()
  public static var decryptedJSONData = [UInt8]()
  private static var decryptedJSON = ""

  public static func JSONFileToString() {        
    guard let JSONFilePath = Bundle.main.url(forResource: "JSONFile", withExtension:"json"), let cipherFilePath = Bundle.main.url(forResource: "JSONCipher", withExtension:"txt") else {
      return
    }

    do {
      let text = try String(contentsOf: cipherFilePath, encoding: String.Encoding.utf8)          
      cipher = [UInt8](text.utf8)
      let data = try Data(contentsOf:JSONFilePath)

      if let JSON = String(data: data, encoding: String.Encoding.utf8) {
        self.JSON = JSON
        JSONData = [UInt8](JSON.utf8)
        //print("data read: \(JSON)")
      } else {
        print("Data to string conversion failed")
      }
    } catch {
      print(error.localizedDescription)
    }
  }

  public static func encodeJSON() {
    // encrypt bytes
    for t in JSONData.enumerated() {
      encryptedJSONData.append(t.element ^ cipher[t.offset])
    }
    print(encryptedJSONData)
  }

  public static func decodeJSON() {
    for t in encryptedJSONData.enumerated() {
      decryptedJSONData.append(t.element ^ cipher[t.offset])
    }
    decryptedJSON = String(bytes: decryptedJSONData, encoding: String.Encoding.utf8)!
    //print(decryptedJSON)
  }

}

Чтобы установить это, вам нужно добавить файл JSONFile.json, содержащий JSON, который вы хотите закодировать. Добавьте его, чтобы скопировать ресурсы пакета. Повторите это для текстового файла с расширением JSONCipher.txt. Убедитесь, что этот файл не содержит речевых меток, так как это приводит к ошибкам и достаточно достаточно для кодирования JSON. Не делайте его слишком большим, так как в противном случае вы получите предупреждение о памяти.

Вы можете поиграть с этим, чтобы закодировать JSON файл с помощью XOR, используя

JSONEncoder.JSONFileToString()
JSONEncoder.encodeJSON()

Затем это будет напечатано на консоли, и вы можете скопировать этот код в файл txt, прикрепленный к вашей инфраструктуре.

Для дешифрования этого файла вы можете протестировать следующее:

JSONEncoder.decodeJSON()

(Раскомментируя оператор print в decodeJSON в структуре JSONEncoder, можно проверить, как это работает)

Если ваш JSON файл слишком велик для этой программы, вы можете использовать этот инструмент: https://www.browserling.com/tools/xor-encrypt и аналогичный XOR Decrypter on тот же домен. Затем вы можете использовать вывод этого кодера для добавления зашифрованного файла JSON в свою инфраструктуру. Просто убедитесь, что вы используете тот же ключ, когда вы декодируете json!

Обратите внимание, что это сохраняет ваш текстовый файл в фактическом проекте: это потенциально небезопасно. Возможно, размещайте файл JSONCipher.txt на сервере и извлекайте его с помощью токена аутентифицированного доступа. Код, который я предоставил, может быть изменен для этого.

Я надеюсь, что это указало вам в правильном направлении для обфускации кода.

Ответ 2

Вы можете добавить содержимое json файла в исходники в качестве кодированной строки base64.

struct JSONFiles {
    internal static let fileOneBase64String = "iVBORw0KGgoAAAANSUhEUgAAAMEAAADLCAYAAADX..."
    static var fileOneJSON: [String: Any] {
        let data = Data(base64Encoded: fileOneBase64String)!
        return try! JSONSerialization.jsonObject(with: data, options: []) as!  [String: Any]
    }
}

Вы можете использовать его позже в любом месте вашей рамки

print(JSONFiles.fileOneJSON)

Надеюсь, он поможет вам

UPDATE: Почему в качестве закодированной строки base64?

  

Основная кодировка base64 base base - вам не нужно избегать специальных символов, содержащихся в строке JSON. Не нужно удалять новые символы строки/символы назначения из строки json перед добавлением в быстрый исходный файл.     См. Пример

  
let string: String = "{ \"name\":\"John\", \"email\": \"[email protected]\" \"age\":30, \"car\":null }"

Но если json более сложный? Если он содержит 10 вложенных уровней, массивы, словари?

Вы можете охватить UnitTests, что значение, содержащееся в fileOneBase64String, может быть декодировано для объекта JSON

import XCTest
@testable import MyAwesomeFramework

class FrameworkTests: XCTestCase {

    func testThatBase64EncodedJSONStringCanBeDecoded() {
        let data = Data(base64Encoded: JSONFiles.fileOneBase64String)
        XCTAssertNotNil(data, "Unable to convert base64 string to Data")
        do {
            _ = try JSONSerialization.jsonObject(with: data, options: [])
        } catch {
            XCTFail("Expected decoded JSON ")
        }
    }
}