CおよびObjective-Cライブラリのインポートの安定性
Kotlin/Nativeは、CおよびObjective-Cライブラリのインポート機能を提供します。 これらのライブラリのサポートは、現在ベータ版です。
ベータ版である主な理由の1つは、CおよびObjective-Cライブラリを使用すると、さまざまなバージョンのKotlin、依存関係、およびXcodeとのコードの互換性に影響を与える可能性があることです。このガイドでは、実際に頻繁に発生する互換性の問題、一部の場合にのみ発生する問題、および仮想的な潜在的な問題も示します。
このガイドでは、CおよびObjective-Cライブラリ、または簡潔にするため_ネイティブライブラリ_は、次のように分けられます:
- プラットフォームライブラリ (各プラットフォーム上の「システム」ネイティブライブラリにアクセスするためにKotlinがデフォルトで提供するもの)
- サードパーティライブラリ (Kotlinの使用に追加設定が必要なその他のすべてのネイティブライブラリ)
これら2種類のネイティブライブラリは、互換性の詳細が異なります。
プラットフォームライブラリ
プラットフォームライブラリはKotlin/Nativeコンパイラに同梱されています。 そのため、プロジェクトで異なるバージョンのKotlinを使用すると、異なるバージョンのプラットフォームライブラリが使用されることになります。 Appleターゲット (iOSなど) の場合、プラットフォームライブラリは、特定のコンパイラバージョンでサポートされているXcodeのバージョンに基づいて生成されます。
Xcode SDKに同梱されているネイティブライブラリAPIは、Xcodeのバージョンごとに変更されます。 そのような変更がネイティブ言語内でソースおよびバイナリ互換であっても、相互運用性の実装によりKotlinでは破壊的となる可能性があります。
その結果、プロジェクトでKotlinバージョンを更新すると、プラットフォームライブラリで破壊的変更が発生する可能性があります。 これは2つのケースで問題となる可能性があります:
プラットフォームライブラリにソースの破壊的変更があり、プロジェクトのソースコードのコンパイルに影響を与える場合。通常、修正は簡単です。
プラットフォームライブラリにバイナリの破壊的変更があり、一部の依存関係に影響を与える場合。通常、簡単な回避策はなく、ライブラリ開発者がその側でこれを修正するまで待つ必要があります (たとえば、Kotlinバージョンを更新することによって)。
そのようなバイナリの非互換性は、リンケージ警告やランタイム例外として現れます。 コンパイル時にそれらを検出したい場合は、
-Xpartial-linkage-loglevel=ERROR
コンパイラオプションを使用して警告をエラーに昇格させてください。
JetBrainsチームがプラットフォームライブラリを生成するために使用するXcodeバージョンを更新する際、プラットフォームライブラリにおける破壊的変更を回避するために合理的な努力をしています。破壊的変更が発生する可能性がある場合は常に、チームは影響分析を実施し、特定の変更を無視するか (影響を受けるAPIが一般的に使用されていないため)、またはアドホックな修正を適用することを決定します。
プラットフォームライブラリにおける破壊的変更のもう1つの潜在的な理由は、ネイティブAPIをKotlinに変換するアルゴリズムの変更です。JetBrainsチームは、そのような場合でも破壊的変更を避けるために合理的な努力をしています。
プラットフォームライブラリからの新しいObjective-Cクラスの使用
Kotlinコンパイラは、デプロイターゲットで利用できないObjective-Cクラスの使用を妨げません。
たとえば、デプロイターゲットがiOS 17.0で、iOS 18.0でのみ登場したクラスを使用する場合、コンパイラは警告せず、アプリケーションはiOS 17.0を搭載したデバイスで起動中にクラッシュする可能性があります。 さらに、そのようなクラッシュは、実行がそれらの使用箇所に到達しない場合でも発生するため、バージョンチェックでそれらを保護するだけでは不十分です。
詳細については、ストロングリンキングを参照してください。
サードパーティライブラリ
システムプラットフォームライブラリとは別に、Kotlin/Nativeはサードパーティのネイティブライブラリのインポートを許可します。 たとえば、CocoaPodsの統合を使用するか、cinteropsの設定を行うことができます。
Xcodeのバージョンが不一致のライブラリのインポート
サードパーティのネイティブライブラリをインポートすると、さまざまなXcodeバージョンとの互換性の問題につながる可能性があります。
ネイティブライブラリを処理する際、コンパイラは通常、ローカルにインストールされているXcodeのヘッダーファイルを使用します。これは、ほとんどすべてのネイティブライブラリのヘッダーが、Xcodeから提供される「標準」ヘッダー (たとえば、stdint.h
) をインポートするためです。
そのため、XcodeのバージョンはKotlinへのネイティブライブラリのインポートに影響を与えます。これは、サードパーティのネイティブライブラリを使用する場合、Mac以外のホストからのAppleターゲットのクロスコンパイルが依然として不可能な理由の1つでもあります。
すべてのKotlinバージョンは、単一のXcodeバージョンと最も互換性があります。これが推奨バージョンであり、対応するKotlinバージョンに対して最も多くテストされています。特定のXcodeバージョンとの互換性は、互換性テーブルで確認してください。
新しいまたは古いXcodeバージョンを使用することはしばしば可能ですが、問題を引き起こす可能性があります。通常、サードパーティのネイティブライブラリのインポートに影響します。
推奨よりも新しいXcodeバージョン
推奨よりも新しいXcodeバージョンを使用すると、いくつかのKotlin機能を破壊する可能性があります。これによって最も影響を受けるのはサードパーティのネイティブライブラリのインポートです。サポートされていないXcodeバージョンでは、まったく動作しないことがよくあります。
推奨よりも古いXcodeバージョン
通常、Kotlinは古いXcodeバージョンとうまく動作します。時折問題が発生する可能性があり、それらはほとんどの場合、次の結果をもたらします:
- KT-71694のように、存在しない型を参照するKotlin API。
- システムライブラリの型がネイティブライブラリのKotlin APIに含まれる。 この場合、プロジェクトは正常にコンパイルされますが、システムネイティブ型がネイティブライブラリパッケージに追加されます。 たとえば、IDEのオートコンプリートでこの型が予期せず表示されることがあります。
Kotlinライブラリが古いXcodeバージョンで正常にコンパイルされる場合、KotlinライブラリAPIでサードパーティライブラリの型を使用しない限り、公開しても安全です。
推移的なサードパーティネイティブ依存関係の使用
プロジェクト内のKotlinライブラリが実装の一部としてサードパーティのネイティブライブラリをインポートする場合、プロジェクトもそのネイティブライブラリにアクセスできます。 これは、Kotlin/Nativeがapi
とimplementation
の依存関係タイプを区別しないためであり、そのためネイティブライブラリは常にapi
依存関係となります。
そのような推移的なネイティブ依存関係を使用すると、より多くの互換性の問題が発生しやすくなります。 たとえば、Kotlinライブラリ開発者による変更により、ネイティブライブラリのKotlin表現が非互換になる可能性があり、Kotlinライブラリを更新する際に互換性の問題につながります。
したがって、推移的な依存関係に頼るのではなく、同じネイティブライブラリとの相互運用性を直接設定してください。 そのためには、互換性の問題を防止するためにカスタムパッケージ名を使用するのと同様に、ネイティブライブラリに別のパッケージ名を使用してください。
ライブラリAPIでのネイティブ型の使用
Kotlinライブラリを公開する場合、ライブラリAPIでのネイティブ型に注意してください。そのような使用箇所は、互換性やその他の問題を修正するために将来的に破壊されることが予想されており、これはライブラリユーザーに影響を与えます。
ライブラリAPIでネイティブ型を使用することが必要な場合があります。これは、ライブラリの目的に必要であるためです。たとえば、Kotlinライブラリが基本的にネイティブライブラリへの拡張機能を提供する場合などです。 それがあなたのケースでない場合は、ライブラリAPIでのネイティブ型の使用を避けるか、制限してください。
この推奨事項は、ライブラリAPIでのネイティブ型の使用にのみ適用され、アプリケーションコードとは関係ありません。 また、ライブラリの実装には適用されません。たとえば:
// 特に注意してください!ネイティブ型がライブラリAPIで使用されています:
public fun createUIView(): UIView
public fun handleThirdPartyNativeType(c: ThirdPartyNativeType)
// 通常通り注意してください。ネイティブ型はライブラリAPIで使用されていません:
internal fun createUIViewController(): UIViewController
public fun getDate(): String = NSDate().toString()
サードパーティライブラリを使用するライブラリの公開
サードパーティのネイティブライブラリを使用するKotlinライブラリを公開する場合、互換性の問題を回避するためにできることがいくつかあります。
カスタムパッケージ名の使用
サードパーティのネイティブライブラリにカスタムパッケージ名を使用すると、互換性の問題を防止するのに役立つ場合があります。
ネイティブライブラリがKotlinにインポートされると、Kotlinパッケージ名が付与されます。一意でない場合、ライブラリユーザーは衝突を経験する可能性があります。たとえば、ネイティブライブラリがユーザーのプロジェクトの他の場所や他の依存関係で同じパッケージ名でインポートされている場合、それら2つの使用箇所は衝突します。
そのような場合、コンパイルはLinking globals named '...': symbol multiply defined!
エラーで失敗する可能性があります。 しかし、他Rのエラーが発生したり、コンパイルが成功することさえあります。
サードパーティのネイティブライブラリにカスタム名を使用するには:
- CocoaPods統合を介してネイティブライブラリをインポートする場合、Gradleビルドスクリプトの
pod {}
ブロックでpackageName
プロパティを使用してください。 cinterops
設定でネイティブライブラリをインポートする場合、設定ブロックでpackageName
プロパティを使用してください。
古いKotlinバージョンとの互換性を確認する
Kotlinライブラリを公開する場合、サードパーティのネイティブライブラリの使用は、他のKotlinバージョンとのライブラリの互換性に影響を与える可能性があります。具体的には:
Kotlin Multiplatformライブラリは前方互換性 (古いコンパイラが新しいコンパイラでコンパイルされたライブラリを使用できること) を保証しません。
実際には、一部のケースでは動作しますが、ネイティブライブラリを使用すると、前方互換性がさらに制限される可能性があります。
Kotlin Multiplatformライブラリは後方互換性 (新しいコンパイラが古いバージョンで生成されたライブラリを使用できること) を提供します。
Kotlinライブラリでネイティブライブラリを使用しても、通常、その後方互換性に影響を与えるべきではありません。 しかし、互換性に影響を与えるより多くのコンパイラバグの可能性を開きます。
静的ライブラリの埋め込みを避ける
ネイティブライブラリをインポートする際、-staticLibrary
コンパイラオプションまたは.def
ファイルのstaticLibraries
プロパティを使用して、関連する静的ライブラリ (.a
ファイル) を含めることが可能です。 その場合、ライブラリユーザーはネイティブ依存関係とリンカオプションを処理する必要がありません。
しかし、含まれている静的ライブラリの使用法をいかなる方法でも設定することは不可能です。つまり、除外することも、置き換える (置換する) こともできません。 そのため、ユーザーは同じ静的ライブラリを含む他のKotlinライブラリとの潜在的な衝突を解決したり、そのバージョンを調整したりすることはできません。
ネイティブライブラリサポートの進化
現在、KotlinプロジェクトでCおよびObjective-Cを使用すると、互換性の問題につながる可能性があります。その一部はこのガイドに記載されています。 それらを修正するためには、将来的にいくつかの破壊的変更が必要になる可能性があります。これは、それ自体が互換性の問題の一因となります。