bazel 모바일 설치

문제 신고 소스 보기 1박 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Android용 빠른 반복 개발

이 페이지에서는 bazel mobile-install의 반복 개발 방식을 설명합니다. Android를 더욱 빠르게 지원하고 있습니다 이 접근 방식의 장점과 기존 앱 설치 방법의 문제를 해결할 수 있습니다.

요약

Android 앱에 대한 작은 변경사항을 매우 빠르게 설치하려면 다음 단계를 따르세요.

  1. 설치하려는 앱의 android_binary 규칙을 찾습니다.
  2. proguard_specs 속성을 삭제하여 Proguard를 사용 중지합니다.
  3. multidex 속성을 native으로 설정합니다.
  4. dex_shards 속성을 10으로 설정합니다.
  5. USB를 통해 ART (Dalvik 아님)를 실행하는 기기를 연결하고 USB를 사용 설정합니다. 디버깅할 수 있습니다
  6. bazel mobile-install :your_target을 실행합니다. 앱 시작이 얼마 남지 않음 평소보다 느립니다
  7. 코드 또는 Android 리소스를 수정합니다.
  8. bazel mobile-install --incremental :your_target을 실행합니다.
  9. 오래 기다리지 않아도 됩니다.

유용할 수 있는 Bazel 명령줄 옵션은 다음과 같습니다.

  • --adb는 사용할 adb 바이너리를 Bazel에 알려줍니다.
  • --adb_argadb의 명령줄에 인수를 추가하는 데 사용할 수 있습니다. 한 가지 유용한 애플리케이션은 설치할 기기를 선택하는 것입니다. 워크스테이션에 여러 기기가 연결된 경우입니다. bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app님이 앱을 자동으로 시작

확실하지 않은 경우 또는 Google에 문의해 주세요.

소개

개발자 도구 모음의 가장 중요한 속성 중 하나는 속도입니다. 코드를 변경하는 것과 피드백을 받기까지 몇 분, 때로는 몇 시간 기다려야 했습니다. 변경사항이 예상대로 작동하는지 여부를 판단해야 합니다.

안타깝게도, .apk 빌드를 위한 기존의 Android 툴체인에는 많은 모놀리식 순차적 단계와 이 모든 것이 Android 앱을 빌드할 수 있습니다. 단 5분을 기다리며 단 한 줄의 데이터를 구축한 Google Google 지도와 같은 대규모 프로젝트에서는 이러한 변화가 이례적인 것이 아니었습니다.

bazel mobile-install를 사용하면 변경 프루닝, 작업 샤딩, 스마트한 Android 내부에 앱 코드를 변경하지 않아도 됩니다.

기존 앱 설치 관련 문제

Android 앱을 빌드하는 데는 다음과 같은 문제가 있습니다.

  • 덱싱. 기본적으로 'dx' 빌드에서 정확히 한 번 호출되고 이전 빌드의 작업을 재사용하는 방법을 알고 있습니다. 하나의 메서드만 변경되었을 뿐입니다.

  • 기기에 데이터를 업로드하는 중입니다. adb가 USB 2.0의 전체 대역폭을 사용하지 않음 크기가 큰 앱은 업로드하는 데 시간이 오래 걸릴 수 있습니다. 앱 전체가 리소스 또는 데이터베이스와 같은 작은 부분만 변경된 경우에도 단일 메서드로 작동하므로 심각한 병목 현상이 될 수 있습니다.

  • 네이티브 코드로 컴파일 Android L에서는 새로운 Android 런타임인 ART를 도입했습니다. 이렇게 하면 앱을 적시에 컴파일하는 대신 미리 컴파일할 수 있습니다. Dalvik 이렇게 하면 긴 설치 대신 앱 속도가 훨씬 빨라집니다. 있습니다. 사용자는 일반적으로 앱을 설치하므로 이는 사용자에게 좋은 절충점이 됩니다. 여러 번 사용하면 개발 속도가 느려지지만 여러 번 설치되고 각 버전은 최대 몇 번 실행됩니다.

bazel mobile-install의 접근 방식

bazel mobile-install에서는 다음과 같은 사항이 개선되었습니다.

  • 샤딩된 덱싱. 앱의 Java 코드를 빌드한 후 Bazel이 클래스를 샤딩합니다. 파일을 거의 동일한 크기의 부분으로 나누고 각각 dx를 있습니다. dx는 마지막 빌드 이후 변경되지 않은 샤드에서 호출되지 않습니다.

  • 증분 파일 전송 Android 리소스, .dex 파일 및 네이티브 라이브러리가 기본 .apk에서 제거되어 별도의 확인할 수 있습니다. 이렇게 하면 코드 및 Android 리소스를 독립적으로 빌드할 수 있습니다 따라서 파일 전송은 시간이 덜 걸리며, .dex 파일만 기기에서 다시 컴파일됩니다

  • .apk 외부에서 앱의 일부를 로드합니다. 작은 스텁 애플리케이션은 Android 리소스, Java 코드, 네이티브 코드를 로드하는 .apk에 삽입 저장한 다음 제어 권한을 있습니다. 몇 가지 특수한 경우를 제외하고 앱에 모두 투명하게 표시됩니다. 참조하세요.

샤딩된 덱싱

샤딩된 덱싱은 상당히 간단합니다. .jar 파일이 빌드되면 도구 이를 거의 동일한 크기의 개별 .jar 파일로 분할한 다음 이전 빌드 이후에 변경된 항목에 대한 dx입니다. 디코더가 는 덱싱할 샤드를 결정하며, Android에만 국한되는 것은 아닙니다. 단지 Bazel의 일반 변경 프루닝 알고리즘입니다.

첫 번째 버전의 샤딩 알고리즘은 단순히 .class 파일을 정렬했습니다. 그런 다음 목록을 동일한 크기의 부분으로 나누었지만, 이것은 차선책: 클래스가 추가되거나 삭제된 경우 (중첩 또는 익명 클래스 포함) 모든 클래스가 알파벳순으로 1씩 이동하게 됩니다. 샤드를 다시 덱싱합니다. 따라서 Java를 샤딩하기로 했습니다. 패키지를 사용하는 것이 좋습니다 물론, 이 경우에도 여전히 새 패키지가 추가되거나 삭제될 때 많은 샤드를 덱싱하지만 그보다 훨씬 적습니다. 단일 클래스를 추가하거나 삭제하는 것보다 더 빈번합니다.

샤드 수는 BUILD 파일에서 제어되며( android_binary.dex_shards 속성) 이상적인 세상에서 Bazel은 가장 적합한 샤드 수를 자동으로 결정하지만 현재 Bazel은 이를 알아야 합니다. 작업을 실행하기 전에 (예: 빌드 중에 실행할 명령어) 최적의 샤드 수를 결정할 수 없기 때문에 그것은 결국 애플리케이션에 얼마나 많은 Java 클래스가 있는지 알 수 없기 때문입니다. 있습니다. 일반적으로, 샤드가 많을수록 빌드가 빨라지고 설치는 중단되지만, 동적인 자동 설치 소프트웨어가 설치되기 때문에 링커는 더 많은 작업을 수행해야 합니다 가장 좋은 부분은 보통 10~50개 정도입니다.

증분 파일 전송

앱을 빌드한 후 다음 단계는 앱을 설치하는 것입니다. 할 수 있습니다. 설치는 다음 단계로 구성됩니다.

  1. .apk 설치 (일반적으로 adb install 사용)
  2. .dex 파일, Android 리소스, 네이티브 라이브러리를 모바일 설치 디렉터리

첫 번째 단계에서는 성과 증분이 많지 않습니다. 앱이 설치되어 있거나 알 수 있습니다. Bazel은 현재 사용자에게 이 단계를 해야 하는지 여부를 나타내야 합니다. --incremental 명령줄 옵션을 통해 모든 경우에 사용할 수 있습니다

두 번째 단계에서는 빌드의 앱 파일을 기기 내 파일과 비교합니다. 기기에 있는 앱 파일과 앱의 파일을 나열하는 매니페스트 파일 체크섬. 모든 새 파일 및 변경된 파일이 기기에 업로드됩니다. 업데이트되고 삭제된 모든 파일은 있습니다. 매니페스트가 없으면 모든 파일이 있습니다.

다음 방법을 사용하여 증분 설치 알고리즘을 속일 수 있습니다. 매니페스트의 체크섬은 변경하지 않고 기기에서 파일을 변경합니다. 이로 인해 네트워크의 파일의 체크섬을 계산하여 이는 설치 시간을 늘릴 만한 가치가 없는 것으로 판단되었습니다.

Stub 애플리케이션

스텁 애플리케이션은 dexes, 네이티브 코드 및 기기 내 mobile-install 디렉터리의 Android 리소스가 발생합니다.

실제 로드는 BaseDexClassLoader를 서브클래스화하여 구현되며 꽤 잘 문서화되어 있습니다. 이는 앱이 클래스가 로드되므로 APK에 있는 모든 애플리케이션 클래스가 업데이트할 수 있도록 기기의 mobile-install 디렉터리에 배치됩니다. (adb install 제외)

이 작업은 클래스가 로드되므로 .apk를 사용하면 이러한 클래스에 대한 변경 사항에 전체 재설치합니다.

이 작업은 Application 클래스에 지정된 AndroidManifest.xml: 스텁 애플리케이션을 사용합니다. 이 앱 시작 시점을 제어하고 클래스 로더와 즉시 리소스 관리자 (해당 생성자)를 Android 프레임워크 내부에 관한 Java 리플렉션

스텁 애플리케이션이 하는 또 다른 작업은 네이티브 라이브러리를 복사하는 것입니다. 다른 위치에 모바일 설치를 통해 설치된 앱 수 이렇게 해야 하는 이유는 동적 링커는 파일에 X 비트를 설정해야 합니다. 이는 루트가 아닌 adb가 액세스할 수 있는 모든 위치에서 실행할 수 있습니다.

이 모든 작업이 완료되면 스텁 애플리케이션은 실제 Application 클래스의 모든 참조가 실제 애플리케이션을 구축할 수 있습니다.

결과

성능

일반적으로 bazel mobile-install를 사용하면 빌드 속도가 4~10배 빨라집니다. 작은 변경 후 큰 앱을 설치할 수 있습니다.

다음은 일부 Google 제품에 대해 계산되었습니다.

물론 이는 변경의 특성, 즉 변경 후 재컴파일하는 것에 따라 달라집니다. 기본 라이브러리를 변경하는 데 시간이 더 오래 걸립니다.

제한사항

스텁 애플리케이션에서 재생하는 트릭이 모든 경우에 효과가 있는 것은 아닙니다. 다음 경우에는 예상대로 작동하지 않는 부분이 강조 표시됩니다.

  • ContextApplication 클래스로 전송되면 ContentProvider#onCreate()입니다. 이 메서드는 애플리케이션 Application 인스턴스를 교체하기 전에 시작되어야 합니다. 클래스이므로 ContentProvider는 여전히 스텁 애플리케이션을 참조합니다. 생성하려고 합니다. 논쟁의 여지가 있지만, 이는 버그가 아닙니다. 이와 같이 Context을(를) 하향 조정해야 하지만 몇 개월 후인 것 같습니다. 담당하고 있습니다.

  • bazel mobile-install님이 설치한 리소스는 앱 다른 앱에서 다음을 통해 리소스에 액세스하는 경우 PackageManager#getApplicationResources()에서 제공하는 리소스입니다. 마지막 비증분 설치입니다.

  • ART를 실행하지 않는 기기 스텁 애플리케이션은 Froyo 이상에서 Dalvik에는 앱이 코드가 특정 영역에서 여러 .dex 파일에 예를 들어 Java 주석이 구체적인 있습니다. 앱이 이러한 버그를 간지럽히지 않는 한 Dalvik과 호환되어야 합니다. 이전 Android 버전에 대한 지원이 포커스)