View in English

  • 메뉴 열기 메뉴 닫기
  • Apple Developer
검색
검색 닫기
  • Apple Developer
  • 뉴스
  • 둘러보기
  • 디자인
  • 개발
  • 배포
  • 지원
  • 계정
페이지에서만 검색

빠른 링크

5 빠른 링크

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 주제
  • 전체 비디오
  • 소개

WWDC25 컬렉션으로 돌아가기

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • Swift 및 Java 상호운용성 살펴보기

    Swift와 Java를 단일 코드베이스에서 함께 사용하는 방법을 알아보세요. Java 프로그램에서 Swift를 사용하거나 Swift 프로그램에서 Java를 사용할 수 있는 swift-java 상호운용성 프로젝트를 소개합니다. swift-Java에서 제공하는 도구 및 라이브러리를 사용하여 두 런타임 간에 상호 운용되는, 안전하고 성능이 뛰어난 코드를 작성하는 방법을 보여드립니다.

    챕터

    • 0:00 - 서론 및 어젠다
    • 2:41 - 런타임 차이점
    • 3:31 - Java Native 메서드
    • 6:29 - SwiftJava
    • 10:13 - Swift에서 Java 호출하기
    • 14:01 - Java에서 Swift 호출하기
    • 20:47 - 요약

    리소스

    • SwiftJava
    • The Swift Programming Language
    • The Swift website
      • HD 비디오
      • SD 비디오

    관련 비디오

    WWDC25

    • C, C++, Swift를 안전하게 함께 사용하기
    • Swift로 메모리 사용량 및 성능 개선하기
    • Swift의 새로운 기능

    WWDC23

    • Swift와 C++ 혼합하기
  • 비디오 검색…

    안녕하세요 저는 Konrad입니다 Swift 언어 팀 소속 엔지니어죠 오늘은 올해 초에 시작한 새로운 상호운용성 프로젝트인 Swift-Java 상호운용성을 소개하고자 합니다 우리는 Swift를 사용할 수 있는 응용 분야를 넓혀 줄 상호운용성에 대해 기대하고 있습니다 상호운용성 즉 인터롭을 사용하면 서서히 Swift를 도입할 수 있죠 다른 언어로 작성된 기존 코드베이스로 말이죠 위험한 대규모 다시 쓰기가 필요 없으며, 대신 기존 코드베이스의 나머지 부분을 건드리지 않고 Swift로 새 기능을 추가하거나 기존 기능을 대체할 수 있습니다 다른 언어로 된 기존 라이브러리를 재사용할 수도 있죠 대신 Swift로 작성된 라이브러리를 사용하도록 할 수 있습니다 인터롭에 접근하는 방식은 단순히 언어에 그치지 않고 각 생태계에 가장 적합한 빌드 도구들과도 통합합니다 C나 C++에는 CMake를 Java에는 Gradle을 사용하죠 C 언어와의 상호운용성은 Swift가 첫선을 보인 날부터 최고의 기능이었습니다 이를 통해 Swift가 기존의 Apple 개발자 생태계와 원활하게 통합되어 결국 이 플랫폼에서 주요 개발 언어가 되었습니다 우리는 2년 전 C++ 상호 운용성을 도입했으며 단일 코드 베이스에서 C++와 Swift 라이브러리를 원활히 혼합하여 Swift를 더 많은 곳에서 사용할 수 있는 가능성이 열렸죠 이에 대한 자세한 내용은 WWDC 2023의 “Swift 및 C++ 혼합하기” 세션 또는 올해의 “C, C++, Swift를 안전하게 함께 사용하기” 세션에서 확인할 수 있습니다 상호운용성에 관해 이야기할 때는 두 방향에 집중합니다 먼저 Swift로 앱을 작성하고 Java로 작성된 일부 코드를 호출할 수 있습니다 또는 Java에서 Swift 호출을 쉽고 효율적으로 만드는 거죠 Swift의 Java 상호운용성은 양방향 모두 지원합니다 각 방향에서 사용하는 도구와 기법은 약간씩 다르나 이 모든 것을 한 프로젝트에서 함께 사용하게 될 수도 있습니다 구체적인 예를 살펴보기 전 Java 런타임과 Swift 런타임의 차이점을 수정하는 법을 살펴보겠습니다 그런 다음 Java 상호 운용성을 활용하는 세 가지 실제 사례를 살펴보죠 먼저 Java의 기존 네이티브 메서드 기능을 사용합니다 그런 다음 Swift에서 전체 Java 라이브러리에 액세스할 수 있도록 만드는 방법을 살펴보겠습니다 마지막으로, 반대로 Java 프로젝트 에서 쉽게 사용할 수 있도록 전체 Swift 라이브러리를 래핑해 보죠 두 런타임을 비교하는 것부터 시작해 보겠습니다 근본적으로 Java 런타임은 Swift가 이미 상호운용성을 갖춘 다른 네이티브 언어들과는 매우 다릅니다 하지만 우리가 좀더 넓게 보면 실제로는 Swift가 Java와 가장 유사한 네이티브 언어일 수도 있죠 두 언어 모두 유사한 상속 모델을 가진 클래스를 제공합니다 둘 다 개발자에게 대체로 투명한 자동 메모리 관리 방법을 제공합니다 둘 다 매우 유사한 일반적 시스템을 제공하지만 런타임에서 다르게 나타납니다 마지막으로, Java의 예외처럼 Swift도 오류가 발생할 수 있죠 런타임에 전달되는 정보의 양은 약간 다르지만 이 역시 마찬가지입니다 중요한 것은 이러한 기능들과 어떻게 상호작용할지 신중히 선택해 실제로 한 언어의 대부분 API를 다른 언어로 표현할 수 있다는 것입니다 이 언어들의 차이점과 유사점을 되짚어 보았으니, 바로 시작해서 기존 Java 애플리케이션을 어떻게 확장할 수 있는지 살펴보겠습니다 간단하게 시작해서 Swift로 단일 함수를 구현하는 데만 집중해 보겠습니다 이를 위해 Java의 네이티브 메서드라는 언어 기능을 사용할 것입니다 Java Native 메소드는 Java Native Interface API 일부이며 줄여서 JNI라고도 합니다 JNI는 1997년부터 Java의 일부가 되었으며, 이는 iPod 출시 이전으로 네이티브 코드와 상호 운용하도록 설계되었죠 이는 성과 목표를 달성하기 작업을 Java 힙 밖으로 옮기거나 Java에 해당하는 네이티브 라이브러리가 없을 경우 해당 네이티브 라이브러리를 사용하기 위해 활용됩니다 여전히 Java와 네이티브 코드가 상호작용하는 주요 방법 중 하나이며, API는 그 이후로 사실 변하지 않았습니다 따라서 JNI 자체를 살펴보는 것 부터 시작하는 것이 합리적이겠죠 JNI에 익숙해지기 위해 지원 라이브러리나 도구 없이 JNI를 사용하려면 일반적으로 따라야 하는 전통적인 단계를 함께 따라가 보겠습니다 Java 애플리케이션 측에서는 네이티브 함수를 정의하고 이를 네이티브 코드로 구현할 것 입니다 JNI가 객체를 네이티브 코드로 전달하는 방식을 설명하기 위해 이 함수의 인수와 반환 유형으로 Uppercase Integer 유형을 사용하고 있습니다 원시 int 값과 달리 이들은 Java 객체이므로 그에 맞게 작업해야 합니다 그런 다음 네이티브 메서드를 포함하는 모든 파일에 Java 컴파일러를 “-h” 플래그와 함께 사용해야 합니다 이렇게 하면 Java Native 메소드가 호출될때 JVM이 호출을 시도하는 C 함수 선언이 포함된 C 헤더 파일이 생성됩니다 선언문은 매우 장황한 이름을 가지고 있습니다 Java_com_example_JNIExample_compute인데 네이티브 메서드의 패키지, 클래스 메서드 이름과 일치합니다 이것은 JNI 환경이라고 불리는 것과 메서드를 호출하는 Java 객체의 This 참조를 위한 jobject 매개변수 그리고 기존 Java 함수 선언의 모든 매개변수들을 받습니다 마지막으로, 이 함수는 각자가 선택한 네이티브 언어로 구현하게 되며 우리는 Swift로 구현하게 됩니다

    코드가 참 많죠? 비록 정형코드가 실제 로직 구현을 압도하고 있지만 실제 로직은 여기에 있습니다 단순한 잡음이 아니죠 사소한 실수로 인해 치명적인 충돌이 발생할 수 있는 기회는 수없이 많습니다 요약하면 JNI는 JVM에서 네이티브 코드를 호출하는 데 잘 지원되는 방법이지만 올바르게 사용하는 것이 매우 어렵습니다 메서드 구현을 효율적으로 만들기 위해 캐싱 등 추가 기법이 필요할 수 있는데 이로 인해 코드가 더욱 복잡해집니다 추가 빌드 단계와 C 헤더 파일도 신경 써야 합니다 모든 메서드 시그니처와 매직 스트링을 수동으로 맞출 때는 오류가 발생하기 쉽습니다 또한 생성하거나 받은 Java 객체 수명 주기를 신중하게 관리해야 하죠 추가 지원 없이 JNI를 사용하는 것도 가능하지만 그다지 좋은 경험은 아닐 것입니다 여기서 Swift와 Java의 상호운용성 작업이 진행되는 새로운 플랫폼인 SwiftJava를 소개합니다 우리는 SwiftJava를 Swift와 Java 개발자들이 두 언어 간 유연하고 안전하며 고성능으로 상호작용 할 수 있도록 만들고 있습니다

    SwiftJava는 몇 가지 구성 요소로 이루어져 있어 필요에 따라 개별적으로 또는 함께 활용할 수 있습니다 먼저 이전 예제에서 살펴본 것처럼 JNI 코드를 훨씬 더 안전하게 처리 가능한 Javakit 라이브러리와 매크로를 제공하는 Swift 패키지입니다 다음은 Java 라이브러리인 SwiftKit입니다 Java 애플리케이션이 Swift 객체를 효과적으로 다룰 수 있도록 하죠 그리고 마지막으로 Swift-Java 명령 도구와 기타 빌드 시스템 통합 기능이 있습니다 예를 들어, SwiftPM 플러그인이나 Gradle 같은 인기 있는 Java 빌드 도구와의 통합 작업도 진행 중입니다 마지막 예시를 다시 보죠 하지만 이번에는 Java 컴파일러 대신 SwiftJava에서 제공하는 도구를 사용할 것입니다 Swift-Java 명령줄 도구를 사용하여 필요 브리징을 생성하고 생성된 소스가 작성될 모듈 이름과 추가 설정을 제공해야 합니다 더 복잡한 프로젝트에서는 SwiftPM이나 사용 중인 다른 빌드 시스템의 빌드 플러그인에 의해 작업이 자동으로 실행되죠 이 워크플로의 결과는 가져온 Java 클래스를 설명하는 데코레이션이 포함된 Swift 파일입니다 Java 유형에 멤버 메서드가 있는 경우 해당 메서드도 대응하는 Swift 타입에 나타납니다. 덕분에 Swift에서 Java 함수들을 다시 호출할 수 있죠 마지막으로 생성된 JNIExampleNativeMethods 프로토콜은 이 유형에 구현 가능한 모든 네이티브 메서드를 포함하죠 우리가 이전에 사용하던 C 헤더를 대체하는 역할을 합니다 실제로 네이티브 컴퓨팅 기능을 구현하려면 생성된 JNIExample 클래스에 확장자를 작성하고 JNIExampleNativeMethods 프로토콜을 준수하면 됩니다 그리고 JavaKit에서 제공하는 JavaImplementation 매크로로 주석 처리도 해야 하죠 다음으로 컴파일러는 필수 함수 서명을 정확히 구현할 수 있도록 도와줄 겁니다 기억해야 할 추가 사항은 JNI 세부 사항을 처리하는 JavaMethod 매크로를 사용해 주석을 달아야 한다는 거죠 SwiftJava 덕분에 우리의 메소드 구현이 훨씬 더 간단해졌습니다 그래서 비즈니스 로직에만 집중할 수 있죠 하지만 더 좋은 점은 우리에게 Swift가 있기 때문에 원하는 Swift 라이브러리를 사용할 수 있다는 점입니다 예를 들어, 암호 알고리즘을 네이티브로 구현해 사용하고 싶을 수 있습니다 Swift 생태계에는 그에 대한 훌륭한 라이브러리가 있어 암호화 모듈을 가져와서 전달된 데이터에 대한 SHA256 해시를 계산할 수 있습니다 이전 JNI 구현에서 겪었던 문제 목록을 기억하실 겁니다 그들 대부분은 JNI에 관한 것이 아니고 올바로 사용하기가 얼마나 어려운지에 대한 내용이었죠 SwiftJava의 JNI 접근 방식 덕분에 많은 상용구를 피할 수 있고 결과 코드는 기본적으로 유지 관리 저장이 훨씬 쉽습니다 우리는 C 헤더와 상호 작용할 필요가 없습니다 대신 잘 입력된 생성된 함수 시그니처를 이용할 수 있죠 디버깅에 오랜 시간이 소요되는 실수를 방지할 수 있습니다 마지막으로, 수작업으로 언어 간 연결고리를 만드는 것과 비료하면 객체 수명 관리가 크게 개선되었습니다 이는 언어 장벽을 넘어 메모리에 안전한 코드 작성에 중요하죠 따라서 전반적으로 손으로 작성하는 것보다 SwiftJava로 모든 종류의 JNI 상호작용을 수행하는 것이 훨씬 더 좋고 안전합니다 SwiftJava에 아직 더 많은 것이 있습니다 다음 상황을 고려해 보죠 여기서 Swift의 Java 라이브러리를 사용할 건데 우리는 다시 동일한 Swift-Java 도구를 사용할 겁니다 그러나 이번에는 단일 유형이 아닌 기존 Java 라이브러리 전체를 어떻게 가져오는지에 대해 초점을 맞춰보겠습니다 예를 들어 Swift에서 널리 사용되는 Apache Commons CSV Java 라이브러리를 사용하려면 라이브러리 자체를 찾아야 할 뿐만 아니라 모든 하위 종속성도 포함됩니다 Java 라이브러리에는 자체 종속성을 가진 전이적 종속성을 많이 갖기 때문에 종속성 해결은 매우 금방 복잡해집니다 다행히도 SwiftJava가 이 작업을 처리해 줄 수 있죠 우리가 할 일은 사용하고 싶은 라이브러리의 아티팩트 좌표를 준비하는 것뿐입니다 일반적으로 온라인에서 쉽게 검색할 수 있습니다 불확실한 경우 팀의 Java 개발자 동료에게 물어보세요 종속성은 세 가지 요소로 표현됩니다 특정 아티팩트를 식별하는 아티팩트 ID 라이브러리를 발행하는 조직을 식별하는 Group ID 그리고 버전 번호죠 다음으로 SwiftJava의 Gradle 통합을 사용해 봅시다 Java 생태계 내 인기 있는 빌드 도구이자 종속성 관리자인데요 Gradle에 이 종속성을 표현하려면 이 세 값 사이에 열을 넣기만 하면 됩니다 이렇게 Gradle이 이해하는 형식 으로 종속성 설명자를 구성했고 이제 우리는 종속성 좌표를 알고 있습니다 JavaApacheCommonsCSV 타깃 다운로드 및 래핑하는 방법에는 두 가지 옵션이 있습니다 첫 번째는 SwiftJava 빌드 도구 플러그인을 쓰는 방법으로 타깃의 swift-java.config 파일 내부 종속성 섹션을 추가하고 해결하고 싶은 모든 루트 종속성을 나열하죠 꽤 괜찮습니다 이제 SwiftPM 프로젝트를 빌드할 때마다 플러그인은 Gradle을 자동으로 호출해 Java 종속성을 해결합니다 단 SwiftPM은 보안 샌드박스를 적용하여 빌드된 플러그인이 임의의 파일이나 네트워크에 접근하지 못하도록 합니다 이 접근 방식을 사용하려면 프로젝트 빌드 시 보안 샌드박스를 비활성화할 수 있습니다 모든 환경에서는 실행 가능하지 않을 수 있어 취할 수 있는 대체 접근 방식이 있습니다 Swift-Java 명령줄 도구의 Resolve 명령을 사용할 수 있죠 구성 파일이 포함된 모듈 이름을 전달하면 도구가 종속성을 해결하고 결과 클래스 경로를 파일에 기록합니다 이 작업은 SwiftPM 빌드 외부에서 수행되므로 샌드박스를 비활성화할 필요가 없죠 하지만 그 말은 결국 프로젝트를 빌드하기 전에 수동으로 의존성 해결을 실행해야 한다는 뜻입니다 이것은 선택의 문제이며 자신의 작업 흐름에 적합한 방식을 선택할 수 있습니다

    어느 방식으로든 Swift에서 Java 라이브러리를 사용할 수 있죠 JavaKit와 JavaApacheCommonsCSV 모듈을 가져오기만 하면 됩니다 그런 다음 Swift 내부에서 JVM을 시작하여 Java 코드를 실행합니다 Swift 애플리케이션 내부에서 Java를 사용할 준비가 되었습니다 여기처럼 JDK의 FileReader를 사용하고 방금 가져온 CSV 라이브러리에 전달합니다 반환된 Java 컬렉션에 대해 Swift의 for-each 루프를 바로 사용할 수도 있습니다

    SwiftJava가 Gradle과 SwiftPM을 모두 활용해 뛰어난 사용자 경험을 제공하는 방법을 배웠습니다 Java 소스 코드를 전혀 수정하지 않고도 전체 Java 라이브러리를 가져올 수 있습니다 생성된 Swift 소스 코드는 JavaKit이 제공하는 JDK 래퍼 유형을 활용하며 사용자 정의 유형도 잘 처리합니다 또한 JavaKit는 필요한 경우 Java 객체에 대한 참조를 전역 참조로 승격시켜 Java 객체의 생명 주기 관리를 간소화하죠 오늘 논의할 마지막 기법은 Swift 라이브러리 전체를 Java 애플리케이션에서 사용할 수 있게 만드는 것입니다 이는 매우 중요한 케이스인데 Swift로 핵심 비즈니스 로직을 구현할 수 있기 때문이며 애플리케이션이나 서비스가 이미 Swift를 채택했는지 여부와 관계없이 이를 사용할 수 있습니다

    상호운용성은 양방향으로 이루어져야 함을 언급했었죠 Java-to-Swift를 훌륭한 경험으로 만들면 더 많은 프로젝트에서 Swift를 사용하고 즐겁게 작업할 수 있으며, 이는 코드베이스에 새로운 언어를 도입하는 데 있어 중요한 사회적 측면입니다 이제 이전 기법을 사용하여 전체 Swift 라이브러리를 노출하려 한다면 Java 측에서 많은 래퍼 함수를 작성해야 할 것입니다 몇 개의 함수라면 괜찮지만 전체 라이브러리에 대해 이야기한다면 다른 접근 방식을 고려할 때입니다 Java 라이브러리를 Swift에 노출하기 위해 했던 것과 유사하게 이제 Java에서 Swift 호출을 최대한 쉽게 만들어 보죠 모든 유형의 Swift 라이브러리를 Java 클래스로 래핑하고 이를 모두 Java 라이브러리로 배포하는 방식으로 진행합니다 이번에는 JNI를 전혀 사용하지 않겠습니다 대신 작년 3월에 안정화되어 현재 Java 22부터 사용 가능한 새로운 Foreign Function 및 Memory API를 사용하게 됩니다 이 API는 네이티브 메모리 제어와 네이티브 호출 구성 방식에 대해 향상된 제어 기능을 제공합니다 어떤 상황에선 JNI 대체 수단 으로 사용할 수도 있습니다 이 새로운 API를 활용함으로써 Java와 Swift의 런타임 및 메모리 관리 간에 아주 깊은 통합을 구축할 수 있게 되죠 그렇지 않고서는 불가능했을 일입니다 이는 Java에서 네이티브 호출을 수행함에 따라 안전성과 성능이 향상되는 결과를 낳습니다 이 예제에서는 Java에 노출하려는 일부 비즈니스 객체를 나타내는 Swift 구조체 유형을 사용해 보죠 이는 값 유형이므로 안정적인 객체 ID가 없습니다 Java 객체로는 표현할 수 없는 것이죠 그렇기 때문에 이 객체를 Java에서 다룰 때에는 주의가 필요합니다 이 객체는 public 속성과 이니셜라이저, 그리고 작동을 위한 몇 가지 방법도 포함하고 있습니다 이 유형을 Java에 노출하기 위해 Swift-Java 명령줄 도구를 사용할 겁니다 하지만 이번에는 약간 다른 방식으로 사용해 보죠 생성된 Swift 및 Java 소스에 대한 Swift 입력 경로와 출력 디렉터리를 제공합니다 그 도구는 입력 경로에 있는 모든 소스를 가져와 Java 클래스를 생성합니다 이 클래스들은 Swift 유형과 함수에 접근하기 위한 접근자 역할을 합니다 필요한 Swift 헬퍼 코드도 함께 생성할 예정입니다 마지막으로, 동적 라이브러리로 빌드된 Swift 코드를 포함한 모든 항목이 컴파일되고 Java 라이브러리로 패키징됩니다 생성된 Java 클래스는 이렇습니다 Struct이기 때문에 Swift 값 인터페이스를 구현합니다 클래스에는 자기 기억 세그먼트가 포함되어 있고 이는 실제 네이티브 메모리의 인스턴스를 가리키는 포인터죠 또한 모든 public 이니셜라이저, 속성, 함수들은 Java 서명에 해당하는 형태로 표현합니다 내부에는 소스 생성된 고성능 코드가 포함되어 있으며 Foreign Function API를 이용해 네이티브 호출을 수행하죠 이제 Java 애플리케이션 내부에서 생성된 Java 소스에 의존 가능하죠 네이티브 Swift 값을 생성 및 관리하려면 SwiftArena가 필요합니다 이 객체는 Swift 객체의 메모리 할당과 수명을 관리합니다 Arena가 준비되면 일반적인 Java 클래스처럼 Swift 값의 생성자를 호출하기만 하면 됩니다 마치 일반적인 Java 클래스인 것처럼 말이죠 이 기회를 빌려 네이티브와 Java 메모리 자원이 이곳에서 어떻게 관리되는지 좀 더 자세히 알아보죠 먼저 새로운 Java 래퍼 객체가 Java 힙에 할당되며 이는 JVM의 가비지 컬렉터에 의해 관리됩니다 소스에서 생성된 생성자는 전달된 SwiftArena를 사용해 네이티브 힙에 Swift 값 유형의 인스턴스를 할당하고 초기화합니다 보통 SwiftyBusiness 구조체 같은 값 유형은 스택에 할당되지만 안정적인 메모리 주소가 필요하므로 대신 힙에 할당합니다 이를 통해 Java 래퍼 객체에서 해당 메모리 주소를 안전하게 가리킬 수 있습니다 결국 Java 래퍼는 더 이상 사용되지 않습니다 그리고 가비지 컬렉터는 이를 수거하고 파기하기로 결정하죠 이렇게 하면 Swift 측에서도 네이티브 인스턴스가 파괴됩니다 따라서 메모리 관리 측면에서는 안전합니다 그러나 Swift와 달리 이처럼 객체 소멸에 의존하는 방식은 GC에 큰 부담을 주죠 해당 객체들을 추적하기 위한 추가 작업이 필요하기 때문입니다 이로 인해 네이티브 Swift 값의 소멸 시점을 예측할 수 없게 되기도 합니다 이것은 시작하기 쉬운 패턴이지만 네이티브 메모리를 더 잘 관리하는 방법을 알려 드리겠습니다 Auto Arena 대신 try-with-resources Java 구문과 Confined Arena 유형을 함께 사용 가능하죠 객체 할당 방식은 여기서도 동일하지만 try-with-resources가 객체 소멸 방식을 변경합니다 구체적으로, triscope가 끝나면 Arena가 닫힙니다 이로 인해 Java 래퍼 객체의 소멸이 트리거되며, 이어서 네이티브 힙의 Swift 값도 소멸하죠 이 접근이 훨씬 낫네요 대규모로 수행하면 문제가 될 수 있는 객체 소멸 처리에 대한 부담을 GC에 지우지 않습니다 또한 많은 Swift 프로그램이 의존하는 정의된 순서에 따른 객체 소멸 특성도 되찾을 수 있게 되었죠 가능한 경우에는 GC에 의존하기보단 ScopedArena를 사용하는 것이 애플리케이션 동작 및 성능에 더 바람직하죠 여기서 우리가 달성한 바를 요약하자면 Swift-Java 명령줄 도구를 한 번 실행하는 것만으로 Swift 라이브러리를 래핑할 수 있었습니다 Swift를 Java 라이브러리로 래핑하여 빌드, 배포 게시할 수 있어 Java 프로젝트에서 간편하게 사용할 수 있고 팀 내 Swift 도입도 더욱 쉬워지죠 또 현대적 Foreign Function 및 Memory API를 사용함으로써 Swift 값 타입까지 포함해 객체 할당 및 수명을 정밀하게 제어할 수 있습니다 오늘은 Swift와 Java 연동을 위한 다양한 기법들을 살펴보았으며 프로젝트의 특정 요구사항에 따라 독립적으로 또는 함께 사용할 수 있습니다 아직 막 시작 단계이고 다듬고 개선할 부분이 많이 남아 있지만 SwiftJava는 이미 두 언어 간 상호운용성을 위한 훌륭한 접근 방식을 제공합니다 SwiftKit 및 JavaKit 지원 라이브러리를 사용하면 언어가 서로 달라도 안전하고 효율적으로 코딩할 수 있죠 JavaKit 매크로와 Swift-Java 명령줄 도구는 유지 관리가 어려운 부분에 필요한 상용구 코드를 자동으로 생성해 줍니다

    마지막으로 이 프로젝트 발전에 함께 해 주시길 바랍니다 완전히 오픈 소스로, Swiftlang Github 조직에서 이용할 수 있죠 아직 해결할 흥미로운 과제와 탐구 아이디어가 많이 있습니다 아직 기여할 준비가 되지 않았지만 Swift 및 Java에 대해 더 알고 싶으시거나 의견과 피드백을 공유하고 싶다면 가장 좋은 방법은 Swift 포럼에 참여하는 것입니다 오늘 시간 내 주셔서 감사합니다 저는 커피 한 잔 마셔야겠네요

    • 9:05 - Implement JNI native methods in Swift

      import JavaKit
      import JavaRuntime
      
      import Crypto
      
      @JavaImplementation("com.example.JNIExample")
      extension JNIExample: JNIExampleNativeMethods {
       
        @JavaMethod
        func compute(_ a: JavaInteger?, _ b: JavaInteger?) -> [UInt8] {
          guard let a else { fatalError("Expected non-null parameter 'a'") }
          guard let a else { fatalError("Expected non-null parameter 'b'") }
          
          let digest = SHA256Digest([a.intValue(), b.intValue()]) // convenience init defined elsewhere
          return digest.toArray()
        }
      }
    • 12:30 - Resolve Java dependencies with swift-java

      swift-java resolve --module-name JavaApacheCommonsCSV
    • 13:05 - Use a Java library from Swift

      import JavaKit
      import JavaKitIO
      import JavaApacheCommonsCSV
      
      let jvm = try JavaVirtualMachine.shared()
      
      let reader = FileReader("sample.csv") // java.io.StringReader
      
      for record in try JavaClass<CSVFormat>().RFC4180.parse(reader)!.getRecords()! {
        for field in record.toList()! {      // Field: hello
          print("Field: \(field)")           // Field: example
        }                                    // Field: csv
      }
      
      print("Done.")
    • 16:22 - Wrap Swift types for Java

      swift-java --input-swift Sources/SwiftyBusiness \ 
                 --java-package com.example.business \
                 --output-swift .build/.../outputs/SwiftyBusiness \
                 --output-java .build/.../outputs/Java ...
    • 18:55 - Create Swift objects from Java

      try (var arena = SwiftArena.ofConfined()) {
        var business = new SwiftyBusiness(..., arena);
      }
    • 0:00 - 서론 및 어젠다
    • Objective-C, C, C++와의 기존 상호 운용성 기능을 기반으로 Swift가 Java와 원활하게 작동할 수 있도록 지원하는 ‘swift-java’라는 실험적 Swift 언어 라이브러리에 대해 알아보세요. 이러한 상호 운용성을 통해 Swift를 기존 Java 코드베이스에 점진적으로 도입하고, 여러 언어 간에 라이브러리를 재사용하며, Swift 라이브러리를 Java 프로젝트와 통합할 수 있습니다. ‘swift-java’가 제공하는 상호 운용성은 Swift에서 Java 코드를 호출하는 것과 반대의 호출을 지원하고 해당 팀은 Java와 Swift 런타임 간의 차이점을 처리하고 Swift 유형으로 변환된 Java 코드에 대한 더 나은 메모리 안전성을 제공하기 위한 도구와 기술을 개발하고 있습니다.

    • 2:41 - 런타임 차이점
    • Swift 및 Java는 클래스, 상속, 자동 메모리 관리, 제네릭, 오류 처리와 같은 공통적인 기능을 공유하지만 런타임에 대해서는 차이점이 있습니다. 이러한 런타임에 대한 차이에도 불구하고 두 언어의 유사성 덕분에 한 언어에서 구현된 대부분의 API를 다른 언어에서도 표현할 수 있습니다.

    • 3:31 - Java Native 메서드
    • Java Native Interface API(JNI)는 1997년 초에 도입되었고 Java Virtual Machine(JVM) 내부에서 실행되는 Java 코드가 Swift와 같은 네이티브 코드와 상호 운용될 수 있도록 해줍니다. 이는 성능을 향상시키거나 Java와 동등한 기능이 없는 네이티브 라이브러리를 활용하기 위해 수행되는 경우가 많습니다. JNI를 사용하려면 Java에서 ‘native’ 함수를 정의하고 해당 C 헤더 파일을 생성해야 합니다. 이 헤더 파일에는 Swift와 같은 네이티브 언어로 구현해야 하는 C 함수 선언이 포함되어 있습니다. 이 프로세스에는 객체 수명 관리, 메서드 시그니처 일치, 오류가 발생하기 쉽고 시간이 많이 걸리는 장황한 보일러플레이트 코드 처리가 포함되어 잠재적으로 치명적인 충돌로 이어질 수 있습니다.

    • 6:29 - SwiftJava
    • SwiftJava는 Swift와 Java 언어 간의 상호 운용성을 향상시킵니다. Swift 및 Java 라이브러리, 명령줄 툴, 빌드 시스템 통합을 포함한 툴 모음을 제공하여 두 언어 간의 상호작용을 단순화하고 보호합니다. ‘swift-java’ 명령줄 툴은 브리징 코드 생성을 자동화하여 수동 C 헤더 상호작용의 필요성을 제거합니다. 이를 통해 객체 수명 관리와 유형 안전성이 개선되어 코드가 더 깔끔해지고 유지 관리하기 쉬워집니다. 이제 비즈니스 로직에 집중해 Swift와 Java 생태계의 모든 힘을 활용하고 수동 JNI 구현과 관련된 일반적인 함정과 오류를 피할 수 있습니다.

    • 10:13 - Swift에서 Java 호출하기
    • SwiftJava를 사용하면 Java 라이브러리를 Swift 프로젝트에 통합할 수 있습니다. Apache Commons CSV와 같은 전체 Java 라이브러리를 가져오려면 ‘groupId’, ‘artifactId’, ‘version’ 등의 아티팩트 좌표를 준비하세요. SwiftJava는 오픈 소스 빌드 시스템인 Gradle을 활용하여 Java 종속성을 해결합니다. Java 종속성을 다운로드하고 래핑하는 데는 두 가지 방법이 있습니다. SwiftPM의 보안 샌드박스를 비활성화해야 하는 SwiftJava 빌드 툴 플러그인을 사용하거나 빌드 프로세스 외부에서 해결을 수행하는 ‘swift-java’ 명령줄 툴의 ‘resolve’ 명령을 사용합니다. Java 종속성이 해결되면 Java 라이브러리를 Swift로 가져오고, Swift 프로세스 내에서 JVM을 시작하며, JavaKit이 객체 수명 관리를 처리하면서 Swift 기능과 함께 Java 코드와 컬렉션을 원활하게 사용할 수 있습니다.

    • 14:01 - Java에서 Swift 호출하기
    • SwiftJava를 사용하면 Swift 라이브러리를 Java 프로젝트에 통합할 수 있습니다. 이를 달성하기 위해 이 WWDC25 세션에서는 Java 측에서 광범위한 래퍼 함수가 필요하지 않은 새로운 접근 방식을 소개합니다. 그 대신 전체 Swift 라이브러리는 Java 22에 도입된 새로운 Foreign Function and Memory API(FFI)를 사용하여 Java 클래스로 래핑됩니다. FFI는 네이티브 메모리에 대한 향상된 제어를 제공하고 Java와 Swift 런타임 및 메모리 관리 시스템 간의 긴밀한 통합을 지원합니다. FFI를 활용하면 Java에서 Swift 코드를 호출하는 프로세스가 더 효율적이고 안전해집니다. ‘swift-java’ 명령줄 툴은 필요한 Java 클래스와 Swift 도우미 코드를 생성하는 데 사용됩니다. 이 툴은 보일러플레이트 생성을 자동화하여 프로세스를 더 간단하게 만들어줍니다. 생성된 Java 클래스는 Swift 유형과 함수에 대한 접근자 역할을 하여 효과적으로 Swift 라이브러리의 기능을 Java에 노출합니다. Java에서 네이티브 Swift 객체를 사용할 때는 적절한 메모리 관리가 매우 중요합니다. 이 논의에서는 Java Garbage Collector(GC)에 의존하는 ‘AutoArena’ 그리고 ‘try-with-resources’와 ‘ConfinedArena’를 사용하는 방법 등 두 가지 접근 방식을 강조합니다. 두 번째 접근 방식은 명확하게 정의되고 체계적인 객체 초기화 해제를 보장하여 성능 문제를 피하고 GC에 부담을 주지 않습니다. 이 기술을 사용하면 Swift로 래핑된 Java 라이브러리를 빌드하고 게시하여 Java 프로젝트에서 쉽게 사용할 수 있습니다. 이를 통해 이미 강력한 Java 활용 능력을 갖춘 팀에서 Swift를 도입하는 과정이 간소화되어 더욱 유연하고 효율적인 개발 환경을 조성할 수 있습니다. SwiftJava의 지속적인 개발은 이러한 기술을 더욱 다듬고 개선하여 두 언어 간 상호 운용성을 위한 강력한 솔루션을 제공하는 것을 목표로 합니다.

    • 20:47 - 요약
    • Swift 프로그래밍 언어는 오픈 소스이며 GitHub뿐만 아니라 SwiftJava와 같은 라이브러리에서 호스팅됩니다. 커뮤니티는 Swift 포럼에서 활발하게 활동하여 학습하고, 아이디어를 공유하며, 피드백을 제공할 수 있습니다.

Developer Footer

  • 비디오
  • WWDC25
  • Swift 및 Java 상호운용성 살펴보기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝 및 AI
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드(영문)
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    Apple Developer 앱 받기
    Copyright © 2025 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침