web-dev-qa-db-ja.com

SwiftフレームワークへのCommonCryptoのインポート

IOS用SwiftフレームワークにCommonCryptoをインポートする方法

SwiftアプリでCommonCryptoを使用する方法を理解しました。ブリッジヘッダーに#import <CommonCrypto/CommonCrypto.h>を追加します。しかし、Swiftフレームワークはブリッジングヘッダをサポートしません。 ドキュメント はこう言います:

純粋なObjective-Cコードベース、純粋なSwiftコードベース、または混在言語のコードベースを持つ外部フレームワークをインポートできます。外部フレームワークをインポートするプロセスは、フレームワークが単一の言語で書かれているか、両方の言語のファイルを含んでいるかにかかわらず同じです。外部フレームワークをインポートするときは、インポートするフレームワークのDefines Moduleビルド設定がYesに設定されていることを確認してください。

次の構文を使用して、異なるターゲット内の任意のSwiftファイルにフレームワークをインポートできます。

import FrameworkName

残念ながら、インポートCommonCryptoは機能しません。傘ヘッダに#import <CommonCrypto/CommonCrypto.h>を追加することもしません。

178
hpique

SwiftフレームワークでCommonCryptoを正常に使用するGitHubプロジェクトを見つけました。 SHA256-Swift 。また、 sqlite3と同じ問題 に関するこの記事は役に立ちました。

上記に基づいて、手順は次のとおりです。

1)プロジェクトディレクトリ内にCommonCryptoディレクトリを作成します。その中に、module.mapファイルを作成します。モジュールマップにより、Swift内でモジュールとしてCommonCryptoライブラリを使用することができます。その内容は以下のとおりです。

module CommonCrypto [system] {
    header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.0.sdk/usr/include/CommonCrypto/CommonCrypto.h"
    link "CommonCrypto"
    export *
}

2)[ビルド設定]のSwift Compiler - 検索パス内で、CommonCryptoディレクトリをインポートパスSwift_INCLUDE_PATHS)に追加します。

Build Settings

3)最後に、他のモジュールと同じようにSwiftファイル内にCommonCryptoをインポートします。例えば:

import CommonCrypto

extension String {

    func hnk_MD5String() -> String {
        if let data = self.dataUsingEncoding(NSUTF8StringEncoding)
        {
            let result = NSMutableData(length: Int(CC_MD5_DIGEST_LENGTH))
            let resultBytes = UnsafeMutablePointer<CUnsignedChar>(result.mutableBytes)
            CC_MD5(data.bytes, CC_LONG(data.length), resultBytes)
            let resultEnumerator = UnsafeBufferPointer<CUnsignedChar>(start: resultBytes, length: result.length)
            let MD5 = NSMutableString()
            for c in resultEnumerator {
                MD5.appendFormat("%02x", c)
            }
            return MD5
        }
        return ""
    }
}

制限事項

別のプロジェクトでカスタムフレームワークを使用すると、コンパイル時にエラーmissing required module 'CommonCrypto'が発生して失敗します。これは、CommonCryptoモジュールがカスタムフレームワークに含まれていないように見えるためです。回避策は、フレームワークを使用するプロジェクトでステップ2(Import Pathsの設定)を繰り返すことです。

モジュールマップはプラットフォームに依存しません(現在は特定のプラットフォーム、iOS 8シミュレータを指しています)。現在のプラットフォームに対してヘッダーパスを作成する方法がわかりません。

IOS 8用のアップデート<=コンパイルを成功させるには、 link "CommonCrypto" という行を削除する必要があります。

更新/編集

次のようなビルドエラーが発生し続けました。

ld:アーキテクチャx86_64の-lCommonCryptoのライブラリが見つかりませんclang:エラー:リンカコマンドが終了コード1で失敗しました(呼び出しを確認するには-vを使用してください)

作成したlink "CommonCrypto"ファイルからmodule.mapという行を削除しない限り。この行を削除したら、正常に構築されました。

82
hpique

もう少し簡単で堅牢なものは、スクリプト実行フェーズで "CommonCryptoModuleMap"という名前のAggregateターゲットを作成し、モジュールマップを自動的に正しいXcode/SDKパスで生成することです。

enter image description hereenter image description here

スクリプトの実行フェーズには、このbashが含まれているはずです。

# This if-statement means we'll only run the main script if the CommonCryptoModuleMap directory doesn't exist
# Because otherwise the rest of the script causes a full recompile for anything where CommonCrypto is a dependency
# Do a "Clean Build Folder" to remove this directory and trigger the rest of the script to run
if [ -d "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap" ]; then
    echo "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap directory already exists, so skipping the rest of the script."
    exit 0
fi

mkdir -p "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap"
cat <<EOF > "${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap/module.modulemap"
module CommonCrypto [system] {
    header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}
EOF

シェルコードと${SDKROOT}を使用すると、特にxcode-selectを使用してベータ版に切り替える場合、または複数のバージョンがあるCIサーバー上に構築している場合は、システムごとに異なるXcode.appパスをハードコードする必要がなくなります非標準の場所にインストールされています。また、SDKをハードコードする必要はないので、これはiOS、macOSなどで機能するはずです。また、プロジェクトのソースディレクトリに何かを置く必要もありません。

このターゲットを作成した後、あなたのライブラリ/フレームワークにTarget Dependencies項目でそれを依存させます:

enter image description here

これにより、フレームワークが構築される前にモジュールマップが確実に生成されます。

macOS notemacOSもサポートしているのなら、作成したばかりの新しい集約ターゲットのSupported Platformsビルド設定にmacosxを追加する必要があります。そうでなければ、モジュールマップを他のフレームワーク製品と共に正しいDebug派生データフォルダーに入れません。

enter image description here

次に、モジュールマップの親ディレクトリ${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMapをSwiftセクションの下の "Import Paths"ビルド設定(Swift_INCLUDE_PATHS)に追加します。

enter image description here

プロジェクトまたはxcconfigレベルで検索パスが定義されている場合は、必ず$(inherited)行を追加してください。

これで終わりです、import CommonCryptoができるはずです

Xcode 10用のアップデート

Xcode 10にはCommonCryptoモジュールマップが同梱されているため、この回避策は不要です。 Xcode 9と10の両方をサポートしたい場合は、Run Scriptフェーズでモジュールマップが存在するかどうかを確認することができます。

COMMON_CRYPTO_DIR="${SDKROOT}/usr/include/CommonCrypto"
if [ -f "${COMMON_CRYPTO_DIR}/module.modulemap" ]
then
   echo "CommonCrypto already exists, skipping"
else
    # generate the module map, using the original code above
fi
131
Mike Weller

実際には「うまくいく」ソリューションを構築することはできますが(module.modulemapSwift_INCLUDE_PATHSの設定を他のソリューションの要求どおりにプロジェクトにコピーする必要はありません)、作成する必要があります。あなた自身のフレームワークにインポートするダミーのフレームワーク/モジュール。プラットフォームに関係なく動作することを確認することもできます(iphoneosiphonesimulator、またはmacosx)。

  1. プロジェクトに新しいフレームワークターゲットを追加し、システムライブラリの名前にを付けます。例:、 "CommonCrypto"。 (アンブレラヘッダは削除できます--- CommonCrypto.h。)

  2. 新しいConfiguration Settings Fileを追加し、それにという名前を付けます(例:、 "CommonCrypto.xcconfig")。 (対象となるものを含めないでください。)次のように入力してください。

    MODULEMAP_FILE[sdk=iphoneos*]        = \
        $(SRCROOT)/CommonCrypto/iphoneos.modulemap
    MODULEMAP_FILE[sdk=iphonesimulator*] = \
        $(SRCROOT)/CommonCrypto/iphonesimulator.modulemap
    MODULEMAP_FILE[sdk=macosx*]          = \
        $(SRCROOT)/CommonCrypto/macosx.modulemap
    
  3. 上記の3つの参照されたモジュールマップファイルを作成し、それらに次のものを追加します。

    • iphoneos.modulemap

      module CommonCrypto [system] {
          header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/CommonCrypto/CommonCrypto.h"
          export *
      }
      
    • iphonesimulator.modulemap

      module CommonCrypto [system] {
          header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/CommonCrypto/CommonCrypto.h"
          export *
      }
      
    • macosx.modulemap

      module CommonCrypto [system] {
          header "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/CommonCrypto/CommonCrypto.h"
          export *
      }
      

    (ベータ版を実行している場合は "Xcode.app"を "Xcode-beta.app"に置き換えます。El Capitanを実行していない場合は10.11を現在のOS SDKに置き換えます。)

  4. プロジェクト設定のInfoタブのConfigurationsで、DebugReleaseの設定をCommonCrypto to CommonCryptoCommonCrypto.xcconfigを参照)。

  5. あなたのフレームワークターゲットのBuild Phasesタブで--- CommonCryptoフレームワークをTarget Dependenciesに追加してください。さらにlibcommonCrypto.dylibバイナリとライブラリをリンクするビルドフェーズに追加してください。

  6. ProductsCommonCrypto.frameworkを選択し、ラッパーのTarget MembershipOptionalに設定されていることを確認します。

これで、ラッパーフレームワークでビルド、実行、およびimport CommonCryptoができるはずです。

例として、 SQLite.Swift がダミーを使用する方法sqlite3.frameworkをご覧ください。

90
stephencelis

この回答では、フレームワークの中で、そしてCocoapodとCarthageを使ってそれを機能させる方法について説明します。

????モジュールマップアプローチ

私はCommonCryptoの周りのラッパーでmodulemapを使っています https://github.com/onmyway133/arcanehttps://github.com/onmyway133/Reindeer

header not foundを取得している方は、ぜひご覧ください https://github.com/onmyway133/Arcane/issues/4 またはxcode-select --installを実行してください

  • module.modulemapを含むフォルダーCCommonCryptoを作成します

      module CCommonCrypto {
        header "/usr/include/CommonCrypto/CommonCrypto.h"
        export *
      }
    
  • [ビルド設定] - > [パスのインポート]に移動します。

      ${SRCROOT}/Sources/CCommonCrypto
    

????モジュールマップアプローチを使ったココアポッド

????パブリックヘッダーアプローチ

????パブリックヘッダーアプローチを使ったココアポッド

????興味深い関連記事

50
onmyway133

良い知らせです。 Swift 4.2(Xcode 10)がついにCommonCryptoを提供します!

Swiftファイルにimport CommonCryptoを追加するだけです。

38
mxcl

警告:iTunesConnectは、この方法を使用しているアプリを拒否 することがあります


私のチームの新しいメンバーが誤ってトップ答えの1つによって与えられた解決策を破ったので、私はそれを CommonCryptoModule と呼ばれる小さなラッパープロジェクトに統合することにしました。手動でインストールすることも、Cocoapodを介してインストールすることもできます。

pod 'CommonCryptoModule', '~> 1.0.2'

それで、あなたがしなければならないのはあなたがCommonCryptoを必要とするモジュールをインポートすることです。

import CommonCryptoModule

他の誰かがこれが役に立つことを願っています。

7

私はMike Wellerの素晴らしい仕事を改善したと思います。

このbashを含むCompile Sourcesフェーズの前にRun Scriptフェーズを追加します。

# This if-statement means we'll only run the main script if the
# CommonCrypto.framework directory doesn't exist because otherwise
# the rest of the script causes a full recompile for anything
# where CommonCrypto is a dependency
# Do a "Clean Build Folder" to remove this directory and trigger
# the rest of the script to run

FRAMEWORK_DIR="${BUILT_PRODUCTS_DIR}/CommonCrypto.framework"

if [ -d "${FRAMEWORK_DIR}" ]; then
echo "${FRAMEWORK_DIR} already exists, so skipping the rest of the script."
exit 0
fi

mkdir -p "${FRAMEWORK_DIR}/Modules"
cat <<EOF > "${FRAMEWORK_DIR}/Modules/module.modulemap"
module CommonCrypto [system] {
    header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}
EOF

ln -sf "${SDKROOT}/usr/include/CommonCrypto" "${FRAMEWORK_DIR}/Headers"

このスクリプトは、正しい場所にmodule.mapを使用して必要最小限のフレームワークを構築してから、XcodeによるフレームワークのBUILT_PRODUCTS_DIRの自動検索に依存します。

元のCommonCryptoインクルードフォルダーをフレームワークのHeadersフォルダーとしてリンクしたので、結果はObjective Cプロジェクトでも機能するはずです。

5
jjrscott

Swift 4.2 with Xcode 1を使っている人のために:

CommonCryptoモジュールは現在システムによって提供されているので、他のシステムフレームワークのように直接インポートすることができます。

import CommonCrypto

4
kubrick G

モジュールマップソリューションは優れていて、SDKの変更に対して堅牢ですが、実際には使用するのが面倒で、他人に物を配るときほど信頼できないことがわかりました。もっと確実なものにするために、私は別の方法を取りました。

ヘッダーをコピーするだけです。

私は知っている、壊れやすい。しかし、AppleはCommonCryptoに大きな変更を加えることはほとんどなく、CommonCryptoを最終的にモジュラーヘッダにすることなしには、大きな変更を加えないという夢を抱いています。

「ヘッダをコピーする」とは、「プリプロセッサが行うのと同じように、必要なヘッダをすべてプロジェクト内の1つの大きなヘッダにカットアンドペーストする」という意味です。あなたがコピーまたは適応できるこの例としては、 RNCryptor.h を参照してください。

これらのファイルはすべてAPSL 2.0の下でライセンスされており、このアプローチでは意図的に著作権とライセンスの表示を守っています。私の連結ステップはMITの下でライセンスされており、それは次のライセンス通知までしか適用されません)。

私はこれがすばらしい解決策ではないと言っていますが、これまでのところ実装とサポートの両方にとって信じられないほど単純な解決策であるように思われます。

4
Rob Napier

@mogstadは@stephencelisソリューションをCocoapodでラップするのに十分親切です。

ポッド 'libCommonCrypto'

利用可能な他のポッドは私にはうまくいきませんでした。

4
Jacob Jennings

これは古い質問です。しかし、私はSwiftプロジェクトでライブラリを使用する別の方法を考え出します。これは、これらの答えで紹介されたフレームワークをインポートしたくない人には役に立つかもしれません。

Swiftプロジェクトでは、Objective-Cブリッジングヘッダを作成し、Objective-CでNSDataカテゴリ(またはライブラリを使用するカスタムクラス)を作成します。唯一の欠点は、すべての実装コードをObjective-Cで書かなければならないことです。例えば:

#import "NSData+NSDataEncryptionExtension.h"
#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (NSDataEncryptionExtension)
- (NSData *)AES256EncryptWithKey:(NSString *)key {
    //do something
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
//do something
}

それからあなたのObjective-Cブリッジングヘッダで、これを追加

#import "NSData+NSDataEncryptionExtension.h"

そして、Swiftクラスでも同じことをします。

public extension String {
func encryp(withKey key:String) -> String? {
    if let data = self.data(using: .utf8), let encrypedData = NSData(data: data).aes256Encrypt(withKey: key) {
        return encrypedData.base64EncodedString()
    }
    return nil
}
func decryp(withKey key:String) -> String? {
    if let data = NSData(base64Encoded: self, options: []), let decrypedData = data.aes256Decrypt(withKey: key) {
        return decrypedData.UTF8String
    }
    return nil
}
}

期待通りに動作します。

2
Terence

あなたのcocoapodsライブラリでCommonCryptoを使う必要がある場合に備えて、jjrscottの答えにcocoapodsの魔法を追加しました。


1) podspecにこの行を追加してください。

s.script_phase = { :name => 'CommonCrypto', :script => 'sh $PROJECT_DIR/../../install_common_crypto.sh', :execution_position => :before_compile }

2)これをあなたのライブラリーのフォルダーまたは好きな場所に保存してください(ただし、それに応じてscript_phaseを変更することを忘れないでください...)

# This if-statement means we'll only run the main script if the
# CommonCrypto.framework directory doesn't exist because otherwise
# the rest of the script causes a full recompile for anything
# where CommonCrypto is a dependency
# Do a "Clean Build Folder" to remove this directory and trigger
# the rest of the script to run
FRAMEWORK_DIR="${BUILT_PRODUCTS_DIR}/CommonCrypto.framework"

if [ -d "${FRAMEWORK_DIR}" ]; then
echo "${FRAMEWORK_DIR} already exists, so skipping the rest of the script."
exit 0
fi

mkdir -p "${FRAMEWORK_DIR}/Modules"
echo "module CommonCrypto [system] {
    header "${SDKROOT}/usr/include/CommonCrypto/CommonCrypto.h"
    export *
}" >> "${FRAMEWORK_DIR}/Modules/module.modulemap"

ln -sf "${SDKROOT}/usr/include/CommonCrypto" "${FRAMEWORK_DIR}/Headers"

魅力のように動作します:)

2
dvdblk

以下の問題があるとします。

ld:-lapple_cryptoのライブラリが見つかりませんclang:error:リンカコマンドが終了コード1で失敗しました(呼び出しを確認するには-vを使用してください)

Xcode 10では、Swift 4.0。 CommonCryptoはフレームワークの一部です。

追加する

  • commonCryptoをインポート

削除する

  • リンクフェーズのCommonCrpto libファイルとビルドフェーズのライブラリ
  • ブリッジヘッダからCommonCryptoをインポートする

これは私のために働いた!

0
SKSN

Xcode 9.2で何かが変わったかどうかはわかりませんが、これを実現する方がはるかに簡単です。私がしなければならなかった唯一のことは、私のフレームワークプロジェクトディレクトリに "CommonCrypto"という名前のフォルダを作成し、その中に以下のように "cc.h"と呼ばれる2つのファイルを作成することです。

#include <CommonCrypto/CommonCrypto.h>
#include <CommonCrypto/CommonRandom.h>

そしてもう1つはmodule.modulemapと呼ばれます。

module CommonCrypto {
    export *
    header "cc.h"
}

(なぜSDKROOT領域のヘッダファイルを直接モジュールマップファイルで参照できないのかわかりませんが、動作させることができませんでした)

3番目のことは、 "Import Paths"設定を見つけて$(SRCROOT)に設定することです。実際には、ルートレベルでそれを望まないのであれば、CommonCryptoフォルダの下に置きたいフォルダに設定することができます。

この後はあなたが使用できるはずです

import CommonCrypto

任意のSwiftファイルとすべての型/関数/ etcにあります。ご利用いただけます。

ただし、警告の言葉 - あなたのアプリケーションがlibCommonCrypto(またはlibcoreCrypto)を使用している場合、あまり洗練されていないハッカーがあなたのアプリケーションにデバッガを接続し、これらの関数に渡されるキーを見つけるのは非常に簡単です。

0
Dylan Nicholson

Xcodeを更新した後も同じことが起こりました。ココアポッドの再インストールやプロジェクトのクリーニングなど、できることはすべて試しましたが、うまくいきませんでした。 restartシステムの後に解決されました。

0
Joey