IOS用SwiftフレームワークにCommonCrypto
をインポートする方法
SwiftアプリでCommonCrypto
を使用する方法を理解しました。ブリッジヘッダーに#import <CommonCrypto/CommonCrypto.h>
を追加します。しかし、Swiftフレームワークはブリッジングヘッダをサポートしません。 ドキュメント はこう言います:
純粋なObjective-Cコードベース、純粋なSwiftコードベース、または混在言語のコードベースを持つ外部フレームワークをインポートできます。外部フレームワークをインポートするプロセスは、フレームワークが単一の言語で書かれているか、両方の言語のファイルを含んでいるかにかかわらず同じです。外部フレームワークをインポートするときは、インポートするフレームワークのDefines Moduleビルド設定がYesに設定されていることを確認してください。
次の構文を使用して、異なるターゲット内の任意のSwiftファイルにフレームワークをインポートできます。
import FrameworkName
残念ながら、インポートCommonCrypto
は機能しません。傘ヘッダに#import <CommonCrypto/CommonCrypto.h>
を追加することもしません。
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
)に追加します。
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
という行を削除しない限り。この行を削除したら、正常に構築されました。
もう少し簡単で堅牢なものは、スクリプト実行フェーズで "CommonCryptoModuleMap"という名前のAggregateターゲットを作成し、モジュールマップを自動的に正しいXcode/SDKパスで生成することです。
スクリプトの実行フェーズには、この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項目でそれを依存させます:
これにより、フレームワークが構築される前にモジュールマップが確実に生成されます。
macOS note:macOS
もサポートしているのなら、作成したばかりの新しい集約ターゲットのSupported Platforms
ビルド設定にmacosx
を追加する必要があります。そうでなければ、モジュールマップを他のフレームワーク製品と共に正しいDebug
派生データフォルダーに入れません。
次に、モジュールマップの親ディレクトリ${BUILT_PRODUCTS_DIR}/CommonCryptoModuleMap
をSwiftセクションの下の "Import Paths"ビルド設定(Swift_INCLUDE_PATHS
)に追加します。
プロジェクトまたは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
実際には「うまくいく」ソリューションを構築することはできますが(module.modulemapとSwift_INCLUDE_PATHS
の設定を他のソリューションの要求どおりにプロジェクトにコピーする必要はありません)、作成する必要があります。あなた自身のフレームワークにインポートするダミーのフレームワーク/モジュール。プラットフォームに関係なく動作することを確認することもできます(iphoneos
、iphonesimulator
、またはmacosx
)。
プロジェクトに新しいフレームワークターゲットを追加し、システムライブラリの名前にを付けます。例:、 "CommonCrypto"。 (アンブレラヘッダは削除できます--- CommonCrypto.h。)
新しい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つの参照されたモジュールマップファイルを作成し、それらに次のものを追加します。
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に置き換えます。)
プロジェクト設定のInfoタブのConfigurationsで、DebugとReleaseの設定をCommonCrypto to CommonCrypto(CommonCrypto.xcconfigを参照)。
あなたのフレームワークターゲットのBuild Phasesタブで--- CommonCryptoフレームワークをTarget Dependenciesに追加してください。さらにlibcommonCrypto.dylibをバイナリとライブラリをリンクするビルドフェーズに追加してください。
ProductsでCommonCrypto.frameworkを選択し、ラッパーのTarget MembershipがOptionalに設定されていることを確認します。
これで、ラッパーフレームワークでビルド、実行、およびimport CommonCrypto
ができるはずです。
例として、 SQLite.Swift がダミーを使用する方法sqlite3.frameworkをご覧ください。
この回答では、フレームワークの中で、そしてCocoapodとCarthageを使ってそれを機能させる方法について説明します。
????モジュールマップアプローチ
私はCommonCryptoの周りのラッパーでmodulemap
を使っています https://github.com/onmyway133/arcane 、 https://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
????モジュールマップアプローチを使ったココアポッド
これがpodspecです https://github.com/onmyway133/Arcane/blob/master/Arcane.podspec
s.source_files = 'Sources/**/*.Swift'
s.xcconfig = { 'Swift_INCLUDE_PATHS' =>
'$(PODS_ROOT)/CommonCryptoSwift/Sources/CCommonCrypto' }
s.preserve_paths = 'Sources/CCommonCrypto/module.modulemap'
module_map
を使用しても機能しません。 https://github.com/CocoaPods/CocoaPods/issues/5271 を参照してください。
path
でLocal Development Podを使用しても機能しません。 https://github.com/CocoaPods/CocoaPods/issues/809 を参照してください。
だからこそ、私のExample Podfile https://github.com/onmyway133/CommonCrypto.Swift/blob/master/Example/CommonCryptoSwiftDemo/Podfile がgitリポジトリを指していることがわかります
target 'CommonCryptoSwiftDemo' do
pod 'CommonCryptoSwift', :git => 'https://github.com/onmyway133/CommonCrypto.Swift'
end
????パブリックヘッダーアプローチ
Ji はlibxml2のラッパーです、そしてそれはパブリックヘッダアプローチを使用します
ヘッダファイルがあります https://github.com/honghaoz/Ji/blob/master/Source/Ji.hTarget Membership
をPublic
に設定
Libxml2用のヘッダファイルのリストがあります https://github.com/honghaoz/Ji/tree/master/Source/Ji-libxml
ビルド設定 - >ヘッダ検索パス
$(SDKROOT)/usr/include/libxml2
ビルド設定 - >その他のリンカフラグがあります
-lxml2
????パブリックヘッダーアプローチを使ったココアポッド
Podspecを見てください https://github.com/honghaoz/Ji/blob/master/Ji.podspec
s.libraries = "xml2"
s.xcconfig = { 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2', 'OTHER_LDFLAGS' => '-lxml2' }
????興味深い関連記事
良い知らせです。 Swift 4.2(Xcode 10)がついにCommonCryptoを提供します!
Swiftファイルにimport CommonCrypto
を追加するだけです。
警告:iTunesConnectは、この方法を使用しているアプリを拒否 することがあります 。
私のチームの新しいメンバーが誤ってトップ答えの1つによって与えられた解決策を破ったので、私はそれを CommonCryptoModule と呼ばれる小さなラッパープロジェクトに統合することにしました。手動でインストールすることも、Cocoapodを介してインストールすることもできます。
pod 'CommonCryptoModule', '~> 1.0.2'
それで、あなたがしなければならないのはあなたがCommonCrypto
を必要とするモジュールをインポートすることです。
import CommonCryptoModule
他の誰かがこれが役に立つことを願っています。
私は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プロジェクトでも機能するはずです。
Swift 4.2 with Xcode 1を使っている人のために:
CommonCryptoモジュールは現在システムによって提供されているので、他のシステムフレームワークのように直接インポートすることができます。
import CommonCrypto
モジュールマップソリューションは優れていて、SDKの変更に対して堅牢ですが、実際には使用するのが面倒で、他人に物を配るときほど信頼できないことがわかりました。もっと確実なものにするために、私は別の方法を取りました。
ヘッダーをコピーするだけです。
私は知っている、壊れやすい。しかし、AppleはCommonCryptoに大きな変更を加えることはほとんどなく、CommonCryptoを最終的にモジュラーヘッダにすることなしには、大きな変更を加えないという夢を抱いています。
「ヘッダをコピーする」とは、「プリプロセッサが行うのと同じように、必要なヘッダをすべてプロジェクト内の1つの大きなヘッダにカットアンドペーストする」という意味です。あなたがコピーまたは適応できるこの例としては、 RNCryptor.h を参照してください。
これらのファイルはすべてAPSL 2.0の下でライセンスされており、このアプローチでは意図的に著作権とライセンスの表示を守っています。私の連結ステップはMITの下でライセンスされており、それは次のライセンス通知までしか適用されません)。
私はこれがすばらしい解決策ではないと言っていますが、これまでのところ実装とサポートの両方にとって信じられないほど単純な解決策であるように思われます。
@mogstadは@stephencelisソリューションをCocoapodでラップするのに十分親切です。
ポッド 'libCommonCrypto'
利用可能な他のポッドは私にはうまくいきませんでした。
これは古い質問です。しかし、私は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
}
}
期待通りに動作します。
あなたの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"
魅力のように動作します:)
以下の問題があるとします。
ld:-lapple_cryptoのライブラリが見つかりませんclang:error:リンカコマンドが終了コード1で失敗しました(呼び出しを確認するには-vを使用してください)
Xcode 10では、Swift 4.0。 CommonCryptoはフレームワークの一部です。
追加する
削除する
これは私のために働いた!
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)を使用している場合、あまり洗練されていないハッカーがあなたのアプリケーションにデバッガを接続し、これらの関数に渡されるキーを見つけるのは非常に簡単です。
Xcodeを更新した後も同じことが起こりました。ココアポッドの再インストールやプロジェクトのクリーニングなど、できることはすべて試しましたが、うまくいきませんでした。 restartシステムの後に解決されました。