Created
November 16, 2025 22:58
-
-
Save exaland/634b2e1d89f29c66f4e678867aa016bb to your computer and use it in GitHub Desktop.
check_elf_alignment for Android 16kb Page Size
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Enhanced ELF Alignment Checker for Android 16KB Page Size Compatibility | |
| # This script checks if your app's native libraries are compatible with 16KB page size devices | |
| # as required by Google Play starting November 1st, 2025 for apps targeting Android 15+ | |
| progname="${0##*/}" | |
| progname="${progname%.sh}" | |
| # Color codes and formatting - detect if colors are supported | |
| if [[ -t 1 ]] && command -v tput >/dev/null 2>&1 && tput colors >/dev/null 2>&1 && [[ $(tput colors) -ge 8 ]]; then | |
| RED="\033[31m" | |
| GREEN="\033[32m" | |
| YELLOW="\033[33m" | |
| BLUE="\033[34m" | |
| CYAN="\033[36m" | |
| PURPLE="\033[35m" | |
| BOLD="\033[1m" | |
| DIM="\033[2m" | |
| ENDCOLOR="\033[0m" | |
| USE_COLORS=true | |
| else | |
| # No color support - use plain text | |
| RED="" | |
| GREEN="" | |
| YELLOW="" | |
| BLUE="" | |
| CYAN="" | |
| PURPLE="" | |
| BOLD="" | |
| DIM="" | |
| ENDCOLOR="" | |
| USE_COLORS=false | |
| fi | |
| # Unicode symbols with fallbacks | |
| if [[ $USE_COLORS == true ]]; then | |
| CHECK_MARK="✓" | |
| CROSS_MARK="✗" | |
| WARNING_MARK="⚠" | |
| INFO_MARK="ℹ" | |
| ROCKET="🚀" | |
| GEAR="⚙" | |
| PACKAGE="📦" | |
| DOCUMENT="📄" | |
| ALERT="🚨" | |
| PARTY="🎉" | |
| TOOLS="🔧" | |
| BOOKS="📚" | |
| ARROW="▶" | |
| else | |
| CHECK_MARK="[OK]" | |
| CROSS_MARK="[X]" | |
| WARNING_MARK="[!]" | |
| INFO_MARK="[i]" | |
| ROCKET="[>]" | |
| GEAR="[*]" | |
| PACKAGE="[P]" | |
| DOCUMENT="[D]" | |
| ALERT="[!]" | |
| PARTY="[*]" | |
| TOOLS="[T]" | |
| BOOKS="[B]" | |
| ARROW=">" | |
| fi | |
| # Enhanced formatting functions | |
| print_banner() { | |
| local title="$1" | |
| local subtitle="$2" | |
| local width=88 | |
| echo | |
| printf "%*s\n" $width | tr ' ' '═' | |
| # Main title | |
| local title_len=${#title} | |
| local title_padding=$(( (width - title_len - 4) / 2 )) | |
| printf "║${BOLD}${BLUE}%*s %s %*s${ENDCOLOR}║\n" \ | |
| $title_padding "" "$title" $title_padding "" | |
| # Subtitle if provided | |
| if [[ -n "$subtitle" ]]; then | |
| local subtitle_len=${#subtitle} | |
| local subtitle_padding=$(( (width - subtitle_len - 4) / 2 )) | |
| printf "║${DIM}%*s %s %*s${ENDCOLOR}║\n" \ | |
| $subtitle_padding "" "$subtitle" $subtitle_padding "" | |
| fi | |
| printf "%*s\n" $width | tr ' ' '═' | |
| echo | |
| } | |
| print_section() { | |
| local icon="$1" | |
| local title="$2" | |
| local description="$3" | |
| echo | |
| echo -e "${BOLD}${BLUE}$icon $title${ENDCOLOR}" | |
| if [[ -n "$description" ]]; then | |
| echo -e "${DIM}$description${ENDCOLOR}" | |
| fi | |
| printf "${BLUE}%*s${ENDCOLOR}\n" 80 | tr ' ' '─' | |
| } | |
| print_status() { | |
| local status="$1" | |
| local message="$2" | |
| local detail="$3" | |
| case $status in | |
| "success") | |
| printf " ${GREEN}${CHECK_MARK}${ENDCOLOR} %s" "$message" | |
| ;; | |
| "error") | |
| printf " ${RED}${CROSS_MARK}${ENDCOLOR} %s" "$message" | |
| ;; | |
| "warning") | |
| printf " ${YELLOW}${WARNING_MARK}${ENDCOLOR} %s" "$message" | |
| ;; | |
| "info") | |
| printf " ${CYAN}${INFO_MARK}${ENDCOLOR} %s" "$message" | |
| ;; | |
| "processing") | |
| printf " ${PURPLE}${GEAR}${ENDCOLOR} %s" "$message" | |
| ;; | |
| esac | |
| if [[ -n "$detail" ]]; then | |
| printf "\n ${DIM}%s${ENDCOLOR}" "$detail" | |
| fi | |
| echo | |
| } | |
| print_subsection() { | |
| local title="$1" | |
| echo | |
| echo -e " ${BOLD}${PURPLE}${ARROW} $title${ENDCOLOR}" | |
| printf " ${PURPLE}%*s${ENDCOLOR}\n" 50 | tr ' ' '┈' | |
| } | |
| print_table_header() { | |
| echo | |
| local line1="┌$(printf '─%.0s' {1..29})┬$(printf '─%.0s' {1..18})┬$(printf '─%.0s' {1..15})┬$(printf '─%.0s' {1..13})┐" | |
| local line2="│ $(printf '%-27s' 'Library') │ $(printf '%-16s' 'Architecture') │ $(printf '%-13s' 'Alignment') │ $(printf '%-11s' 'Status') │" | |
| local line3="├$(printf '─%.0s' {1..29})┼$(printf '─%.0s' {1..18})┼$(printf '─%.0s' {1..15})┼$(printf '─%.0s' {1..13})┤" | |
| echo -e "${CYAN}$line1${ENDCOLOR}" | |
| echo -e "${BOLD}${CYAN}$line2${ENDCOLOR}" | |
| echo -e "${CYAN}$line3${ENDCOLOR}" | |
| } | |
| print_table_row() { | |
| local lib="$1" | |
| local arch="$2" | |
| local alignment="$3" | |
| local status="$4" | |
| local is_critical="$5" | |
| local status_symbol | |
| local status_color | |
| local status_text | |
| if [[ $status == "ALIGNED" ]]; then | |
| status_symbol="$CHECK_MARK" | |
| status_color="$GREEN" | |
| status_text="PASS" | |
| else | |
| status_symbol="$CROSS_MARK" | |
| if [[ $is_critical == "true" ]]; then | |
| status_color="$RED" | |
| status_text="FAIL" | |
| else | |
| status_color="$YELLOW" | |
| status_text="WARN" | |
| fi | |
| fi | |
| # Truncate library name if too long | |
| local display_lib="$lib" | |
| if [[ ${#lib} -gt 27 ]]; then | |
| display_lib="${lib:0:24}..." | |
| fi | |
| printf "${CYAN}│${ENDCOLOR} %-27s ${CYAN}│${ENDCOLOR} %-16s ${CYAN}│${ENDCOLOR} %-13s ${CYAN}│${ENDCOLOR} ${status_color}%s %-7s${ENDCOLOR} ${CYAN}│${ENDCOLOR}\n" \ | |
| "$display_lib" "$arch" "$alignment" "$status_symbol" "$status_text" | |
| if [[ $is_critical == "true" && $status == "UNALIGNED" ]]; then | |
| printf "${CYAN}│${ENDCOLOR} ${RED}%-75s${ENDCOLOR} ${CYAN}│${ENDCOLOR}\n" " ${ALERT} CRITICAL: Required for Google Play compliance!" | |
| fi | |
| } | |
| print_table_footer() { | |
| local line="└$(printf '─%.0s' {1..29})┴$(printf '─%.0s' {1..18})┴$(printf '─%.0s' {1..15})┴$(printf '─%.0s' {1..13})┘" | |
| echo -e "${CYAN}$line${ENDCOLOR}" | |
| echo | |
| } | |
| print_summary_box() { | |
| local title="$1" | |
| local status="$2" # success, warning, error | |
| shift 2 | |
| local lines=("$@") | |
| local box_color | |
| local title_color | |
| case $status in | |
| "success") box_color="$GREEN"; title_color="$GREEN" ;; | |
| "warning") box_color="$YELLOW"; title_color="$YELLOW" ;; | |
| "error") box_color="$RED"; title_color="$RED" ;; | |
| *) box_color="$BLUE"; title_color="$BLUE" ;; | |
| esac | |
| local width=78 | |
| echo | |
| printf "${box_color}┌%*s┐${ENDCOLOR}\n" $((width-2)) | tr ' ' '─' | |
| # Title | |
| local title_len=${#title} | |
| local title_padding=$(( (width - title_len - 4) / 2 )) | |
| printf "${box_color}│${ENDCOLOR}${BOLD}${title_color}%*s %s %*s${ENDCOLOR}${box_color}│${ENDCOLOR}\n" \ | |
| $title_padding "" "$title" $title_padding "" | |
| printf "${box_color}├%*s┤${ENDCOLOR}\n" $((width-2)) | tr ' ' '─' | |
| # Content lines | |
| for line in "${lines[@]}"; do | |
| printf "${box_color}│${ENDCOLOR} %-*s ${box_color}│${ENDCOLOR}\n" $((width-4)) "$line" | |
| done | |
| printf "${box_color}└%*s┘${ENDCOLOR}\n" $((width-2)) | tr ' ' '─' | |
| echo | |
| } | |
| cleanup_trap() { | |
| if [ -n "${tmp}" -a -d "${tmp}" ]; then | |
| print_status "processing" "Cleaning up temporary files..." | |
| rm -rf "${tmp}" | |
| fi | |
| exit $1 | |
| } | |
| usage() { | |
| print_banner "Android 16KB Page Size Compatibility Checker" "Google Play Compliance Tool" | |
| echo -e "${BOLD}DESCRIPTION:${ENDCOLOR}" | |
| echo " This tool verifies that your Android app's native libraries are compatible" | |
| echo " with 16KB page size devices, as required by Google Play starting November 1st, 2025." | |
| echo | |
| echo -e "${BOLD}USAGE:${ENDCOLOR}" | |
| echo -e " ${GREEN}$progname${ENDCOLOR} ${CYAN}[input-path|input-APK|input-APEX]${ENDCOLOR}" | |
| echo | |
| echo -e "${BOLD}EXAMPLES:${ENDCOLOR}" | |
| echo -e " ${DIM}# Check an APK file${ENDCOLOR}" | |
| echo -e " $progname ${CYAN}app/build/outputs/apk/release/app-release.apk${ENDCOLOR}" | |
| echo | |
| echo -e " ${DIM}# Check a directory of native libraries${ENDCOLOR}" | |
| echo -e " $progname ${CYAN}/path/to/native/libs/${ENDCOLOR}" | |
| echo | |
| echo -e "${BOLD}WHAT THIS TOOL CHECKS:${ENDCOLOR}" | |
| echo -e " ${CHECK_MARK} APK zip-alignment for 16KB boundaries (requires build-tools 35.0.0+)" | |
| echo -e " ${CHECK_MARK} ELF segment alignment in native libraries (arm64-v8a and x86_64)" | |
| echo -e " ${CHECK_MARK} Compliance with Android 16KB page size requirements" | |
| echo | |
| echo -e "${BOLD}RESULT MEANINGS:${ENDCOLOR}" | |
| echo -e " ${GREEN}${CHECK_MARK} PASS${ENDCOLOR} - Library is compatible with 16KB page sizes (2**14 or higher)" | |
| echo -e " ${RED}${CROSS_MARK} FAIL${ENDCOLOR} - Library needs recompilation with 16KB ELF alignment" | |
| echo -e " ${YELLOW}${WARNING_MARK} WARN${ENDCOLOR} - Non-critical architecture but should be fixed" | |
| echo | |
| } | |
| # Enhanced dependency checking | |
| check_dependencies() { | |
| print_section "$GEAR" "Dependency Check" "Verifying required tools are available" | |
| local missing_tools=() | |
| local available_tools=() | |
| # Check each tool | |
| local tools=("objdump" "unzip" "file") | |
| for tool in "${tools[@]}"; do | |
| if command -v "$tool" >/dev/null 2>&1; then | |
| available_tools+=("$tool") | |
| print_status "success" "$tool" "$(which "$tool")" | |
| else | |
| missing_tools+=("$tool") | |
| print_status "error" "$tool not found" | |
| fi | |
| done | |
| if [ ${#missing_tools[@]} -gt 0 ]; then | |
| echo | |
| print_subsection "Installation Instructions" | |
| for tool in "${missing_tools[@]}"; do | |
| case $tool in | |
| objdump) | |
| print_status "info" "Install objdump:" "macOS: Xcode Command Line Tools or Android NDK's llvm-objdump" | |
| print_status "info" "" "Linux: sudo apt-get install binutils (Ubuntu/Debian)" | |
| ;; | |
| unzip) | |
| print_status "info" "Install unzip:" "Usually pre-installed on most systems" | |
| print_status "info" "" "Linux: sudo apt-get install unzip" | |
| ;; | |
| file) | |
| print_status "info" "Install file:" "Usually pre-installed on most systems" | |
| print_status "info" "" "Linux: sudo apt-get install file" | |
| ;; | |
| esac | |
| echo | |
| done | |
| exit 1 | |
| fi | |
| print_status "success" "All dependencies satisfied" "${#available_tools[@]} tools available" | |
| } | |
| # Validate input arguments | |
| if [ ${#} -ne 1 ]; then | |
| usage | |
| exit 1 | |
| fi | |
| case ${1} in | |
| --help | -h | -\?) | |
| usage | |
| exit 0 | |
| ;; | |
| *) | |
| dir="${1}" | |
| ;; | |
| esac | |
| # Validate input file/directory | |
| if ! [ -f "${dir}" -o -d "${dir}" ]; then | |
| print_status "error" "Invalid input: ${dir}" | |
| echo " Please provide a valid APK file, APEX file, or directory containing native libraries." | |
| exit 1 | |
| fi | |
| # Check dependencies before proceeding | |
| check_dependencies | |
| print_banner "ANALYSIS IN PROGRESS" "Checking 16KB Page Size Compatibility" | |
| print_status "processing" "Target: $(basename "${dir}")" | |
| print_status "info" "Compliance Deadline: November 1st, 2025" | |
| print_status "info" "Requirement: Apps targeting Android 15+ must support 16KB pages" | |
| # APK Processing | |
| if [[ "${dir}" == *.apk ]]; then | |
| trap 'cleanup_trap' EXIT | |
| print_section "$PACKAGE" "APK Analysis" "Processing Android Package file" | |
| # Enhanced zipalign check | |
| if command -v zipalign >/dev/null 2>&1; then | |
| if { zipalign --help 2>&1 | grep -q "\-P <pagesize_kb>"; }; then | |
| print_status "processing" "Checking APK zip-alignment for 16KB boundaries..." | |
| zip_result=$(zipalign -v -c -P 16 4 "${dir}" 2>&1) | |
| zip_exit_code=$? | |
| if [ $zip_exit_code -eq 0 ]; then | |
| print_status "success" "APK zip-alignment verification passed" | |
| else | |
| print_status "error" "APK zip-alignment verification failed" | |
| echo " ${DIM}Details:${ENDCOLOR}" | |
| echo "$zip_result" | grep -E 'lib/arm64-v8a|lib/x86_64|Verification|would be' | sed 's/^/ /' || echo " $zip_result" | |
| fi | |
| else | |
| print_status "warning" "zipalign version doesn't support 16KB alignment checks" | |
| print_status "info" "Solution: Update to Android SDK build-tools 35.0.0+" | |
| echo " ${DIM}Update via Android Studio → SDK Manager → SDK Tools${ENDCOLOR}" | |
| echo " ${DIM}Or run: sdkmanager \"build-tools;35.0.0\"${ENDCOLOR}" | |
| fi | |
| else | |
| print_status "warning" "zipalign not found in PATH" | |
| print_status "info" "Ensure Android SDK build-tools are installed and in PATH" | |
| fi | |
| # Extract APK | |
| dir_filename=$(basename "${dir}") | |
| tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX") | |
| if [ ! -d "${tmp}" ]; then | |
| print_status "error" "Failed to create temporary directory" | |
| exit 1 | |
| fi | |
| print_status "processing" "Extracting native libraries from APK..." | |
| if ! unzip -q "${dir}" "lib/*" -d "${tmp}" 2>/dev/null; then | |
| print_summary_box "NO NATIVE LIBRARIES FOUND" "success" \ | |
| "${PARTY} Your app contains only Java/Kotlin code!" \ | |
| "" \ | |
| "${CHECK_MARK} Apps without native libraries automatically support 16KB devices" \ | |
| "${CHECK_MARK} No additional changes required for Google Play compliance" \ | |
| "${CHECK_MARK} You're all set for the November 1st, 2025 deadline!" | |
| cleanup_trap 0 | |
| fi | |
| dir="${tmp}" | |
| fi | |
| # APEX Processing | |
| if [[ "${dir}" == *.apex ]]; then | |
| trap 'cleanup_trap' EXIT | |
| print_section "$DOCUMENT" "APEX Analysis" "Processing Android Pony EXpress file" | |
| if ! command -v deapexer >/dev/null 2>&1; then | |
| print_status "error" "deapexer tool not found" | |
| echo " Please ensure Android SDK tools are properly installed and in your PATH." | |
| exit 1 | |
| fi | |
| dir_filename=$(basename "${dir}") | |
| tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX") | |
| if [ ! -d "${tmp}" ]; then | |
| print_status "error" "Failed to create temporary directory" | |
| exit 1 | |
| fi | |
| print_status "processing" "Extracting APEX contents..." | |
| if ! deapexer extract "${dir}" "${tmp}"; then | |
| print_status "error" "Failed to extract APEX file" | |
| cleanup_trap 1 | |
| fi | |
| dir="${tmp}" | |
| fi | |
| # Track libraries for enhanced summary | |
| unaligned_libs=() | |
| aligned_libs=() | |
| critical_unaligned_libs=() | |
| non_critical_unaligned_libs=() | |
| total_libs=0 | |
| critical_libs=0 | |
| print_section "$GEAR" "ELF Segment Analysis" "Scanning native libraries for 16KB alignment compliance" | |
| # Find all native libraries | |
| matches="$(find "${dir}" -type f -name '*.so' 2>/dev/null)" | |
| if [ -z "$matches" ]; then | |
| # Also check for ELF files without .so extension | |
| matches="$(find "${dir}" -type f -exec file {} \; 2>/dev/null | grep 'ELF' | cut -d: -f1)" | |
| fi | |
| if [ -z "$matches" ]; then | |
| print_summary_box "NO NATIVE LIBRARIES DETECTED" "success" \ | |
| "${PARTY} Your app uses only Java/Kotlin code!" \ | |
| "" \ | |
| "${CHECK_MARK} No native library alignment issues to worry about" \ | |
| "${CHECK_MARK} Already compatible with 16KB page size devices" \ | |
| "${CHECK_MARK} Ready for Google Play's November 1st, 2025 requirement!" | |
| cleanup_trap 0 | |
| fi | |
| print_status "info" "Found native libraries - analyzing ELF segment alignment..." | |
| print_table_header | |
| IFS=$'\n' | |
| for match in $matches; do | |
| # Skip non-ELF files and nested packages | |
| if [[ "${match}" == *".apk" ]]; then | |
| continue | |
| fi | |
| if [[ "${match}" == *".apex" ]]; then | |
| continue | |
| fi | |
| # Verify it's actually an ELF file | |
| if ! [[ $(file "${match}" 2>/dev/null) == *"ELF"* ]]; then | |
| continue | |
| fi | |
| total_libs=$((total_libs + 1)) | |
| # Determine architecture and criticality | |
| arch="unknown" | |
| is_critical="false" | |
| if [[ "${match}" == *"arm64-v8a"* ]]; then | |
| arch="arm64-v8a" | |
| is_critical="true" | |
| critical_libs=$((critical_libs + 1)) | |
| elif [[ "${match}" == *"x86_64"* ]]; then | |
| arch="x86_64" | |
| is_critical="true" | |
| critical_libs=$((critical_libs + 1)) | |
| elif [[ "${match}" == *"armeabi-v7a"* ]]; then | |
| arch="armeabi-v7a" | |
| elif [[ "${match}" == *"x86"* ]]; then | |
| arch="x86" | |
| fi | |
| # Check ELF segment alignment | |
| res="$(objdump -p "${match}" 2>/dev/null | grep LOAD | awk '{ print $NF }' | head -1)" | |
| if [ -z "$res" ]; then | |
| print_table_row "$(basename "${match}")" "$arch" "UNKNOWN" "FAILED" "$is_critical" | |
| continue | |
| fi | |
| # Check if alignment meets 16KB requirement (2**14 or higher) | |
| if [[ $res =~ 2\*\*(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then | |
| print_table_row "$(basename "${match}")" "$arch" "$res" "ALIGNED" "$is_critical" | |
| aligned_libs+=("${match}") | |
| else | |
| print_table_row "$(basename "${match}")" "$arch" "$res" "UNALIGNED" "$is_critical" | |
| unaligned_libs+=("${match}") | |
| if [[ "$is_critical" == "true" ]]; then | |
| critical_unaligned_libs+=("${match}") | |
| else | |
| non_critical_unaligned_libs+=("${match}") | |
| fi | |
| fi | |
| done | |
| print_table_footer | |
| # Enhanced Summary Section | |
| if [ ${#unaligned_libs[@]} -gt 0 ]; then | |
| # Failure case - unaligned libraries found | |
| summary_lines=( | |
| "${ALERT} ACTION REQUIRED: Unaligned native libraries detected!" | |
| "" | |
| "Analysis Results:" | |
| " • Total libraries scanned: $total_libs" | |
| " • Critical architectures (64-bit): $critical_libs" | |
| " • Libraries aligned: ${#aligned_libs[@]}" | |
| " • Libraries UNALIGNED: ${#unaligned_libs[@]}" | |
| ) | |
| if [ ${#critical_unaligned_libs[@]} -gt 0 ]; then | |
| summary_lines+=(" • Critical failures: ${#critical_unaligned_libs[@]} (MUST FIX)") | |
| fi | |
| if [ ${#non_critical_unaligned_libs[@]} -gt 0 ]; then | |
| summary_lines+=(" • Non-critical warnings: ${#non_critical_unaligned_libs[@]} (SHOULD FIX)") | |
| fi | |
| summary_lines+=("") | |
| summary_lines+=("Google Play Compliance: FAILED") | |
| summary_lines+=("Deadline: November 1st, 2025") | |
| print_summary_box "COMPATIBILITY CHECK FAILED" "error" "${summary_lines[@]}" | |
| # Detailed library breakdown | |
| if [ ${#critical_unaligned_libs[@]} -gt 0 ]; then | |
| print_subsection "Critical Libraries Requiring Immediate Attention" | |
| for lib in "${critical_unaligned_libs[@]}"; do | |
| arch_type="64-bit" | |
| [[ "${lib}" == *"arm64-v8a"* ]] && arch_type="ARM64" | |
| [[ "${lib}" == *"x86_64"* ]] && arch_type="x86_64" | |
| print_status "error" "$(basename "$lib")" "$arch_type architecture - Required for Google Play" | |
| done | |
| fi | |
| if [ ${#non_critical_unaligned_libs[@]} -gt 0 ]; then | |
| print_subsection "Non-Critical Libraries (Recommended to Fix)" | |
| for lib in "${non_critical_unaligned_libs[@]}"; do | |
| arch_type="32-bit" | |
| [[ "${lib}" == *"armeabi-v7a"* ]] && arch_type="ARMv7" | |
| [[ "${lib}" == *"x86"* ]] && arch_type="x86" | |
| print_status "warning" "$(basename "$lib")" "$arch_type architecture" | |
| done | |
| fi | |
| # Comprehensive fix instructions | |
| print_section "$TOOLS" "How to Fix Unaligned Libraries" "Step-by-step guide to achieve 16KB compatibility" | |
| print_subsection "Step 1: Update Your Build Environment" | |
| print_status "info" "Android Gradle Plugin (AGP)" "Upgrade to version 8.5.1 or higher" | |
| print_status "info" "Android NDK" "Update to NDK r27 or higher (r28+ recommended)" | |
| print_status "info" "Build Tools" "Ensure Android SDK build-tools 35.0.0+ for zipalign" | |
| print_subsection "Step 2: Configure 16KB ELF Alignment" | |
| echo | |
| echo -e "${BOLD}For NDK r28 and newer:${ENDCOLOR}" | |
| print_status "success" "Automatic Support" "16KB alignment enabled by default - no changes needed!" | |
| echo | |
| echo -e "${BOLD}For NDK r27:${ENDCOLOR}" | |
| print_status "info" "Gradle Configuration" "Add to your app/build.gradle:" | |
| echo -e "${DIM} android {" | |
| echo -e " defaultConfig {" | |
| echo -e " externalNativeBuild {" | |
| echo -e " cmake {" | |
| echo -e " arguments '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'" | |
| echo -e " }" | |
| echo -e " }" | |
| echo -e " }" | |
| echo -e " }${ENDCOLOR}" | |
| print_status "info" "NDK-Build Configuration" "Add to Application.mk:" | |
| echo -e "${DIM} APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true${ENDCOLOR}" | |
| echo | |
| echo -e "${BOLD}For NDK r26 and older:${ENDCOLOR}" | |
| print_status "info" "Manual Linker Flags" "Add to your native build configuration:" | |
| echo -e "${DIM} # For Android.mk:" | |
| echo -e " LOCAL_LDFLAGS += \"-Wl,-z,max-page-size=16384\"" | |
| echo | |
| echo -e " # For CMakeLists.txt:" | |
| echo -e " target_link_options(\${CMAKE_PROJECT_NAME} PRIVATE \"-Wl,-z,max-page-size=16384\")${ENDCOLOR}" | |
| print_subsection "Step 3: Update Library Packaging" | |
| print_status "info" "AGP 8.5.1+" "Uncompressed libraries used by default (no changes needed)" | |
| print_status "info" "Older AGP versions" "Add to app/build.gradle:" | |
| echo -e "${DIM} android {" | |
| echo -e " packagingOptions {" | |
| echo -e " jniLibs {" | |
| echo -e " useLegacyPackaging = true" | |
| echo -e " }" | |
| echo -e " }" | |
| echo -e " }${ENDCOLOR}" | |
| print_subsection "Step 4: Build and Verify" | |
| print_status "processing" "Clean Build" "Run ./gradlew clean" | |
| print_status "processing" "Rebuild Project" "Run ./gradlew assembleRelease" | |
| print_status "processing" "Re-run This Script" "Verify all libraries are now aligned" | |
| print_status "processing" "Test on Device" "Use Android 15 emulator with 16KB system image" | |
| print_section "$BOOKS" "Additional Resources" "Learn more about 16KB page size support" | |
| print_status "info" "Official Guide" "https://developer.android.com/guide/practices/page-sizes" | |
| print_status "info" "NDK Documentation" "https://developer.android.com/ndk/guides/" | |
| print_status "info" "Testing Guide" "Use 'adb shell getconf PAGE_SIZE' (should return 16384)" | |
| print_status "info" "Emulator Setup" "Android 15 system images with 16KB page size" | |
| final_message="" | |
| if [ ${#critical_unaligned_libs[@]} -gt 0 ]; then | |
| final_message="CRITICAL: Fix required for Google Play compliance by November 1st, 2025!" | |
| else | |
| final_message="Warning: Non-critical issues found - recommended to fix for complete compatibility" | |
| fi | |
| print_summary_box "NEXT STEPS" "error" \ | |
| "$final_message" \ | |
| "" \ | |
| "1. Update your build tools and NDK version" \ | |
| "2. Apply the configuration changes above" \ | |
| "3. Clean and rebuild your project" \ | |
| "4. Run this script again to verify fixes" \ | |
| "5. Test thoroughly on 16KB devices/emulator" | |
| cleanup_trap 1 | |
| else | |
| # Success case - all libraries aligned | |
| summary_lines=( | |
| "${PARTY} All native libraries are properly aligned!" | |
| "" | |
| "Analysis Results:" | |
| " • Total libraries scanned: $total_libs" | |
| " • Critical architectures: $critical_libs" | |
| " • All libraries: ${#aligned_libs[@]}/${total_libs} ALIGNED" | |
| "" | |
| "Google Play Compliance: PASSED ${CHECK_MARK}" | |
| "Ready for November 1st, 2025 deadline!" | |
| ) | |
| print_summary_box "COMPATIBILITY CHECK PASSED" "success" "${summary_lines[@]}" | |
| print_section "$ROCKET" "Next Steps" "Ensure complete 16KB compatibility" | |
| print_status "success" "Library Alignment" "All ELF segments properly aligned for 16KB pages" | |
| print_status "info" "Runtime Testing" "Test on Android 15 emulator with 16KB system image" | |
| print_status "info" "Code Review" "Check for hardcoded PAGE_SIZE dependencies in your code" | |
| print_status "info" "Third-party SDKs" "Verify all dependencies are 16KB compatible" | |
| print_status "info" "Zipalign Verification" "Run: zipalign -c -P 16 -v 4 your-app.apk" | |
| print_subsection "Testing Commands" | |
| echo -e "${DIM} # Verify page size on device/emulator${ENDCOLOR}" | |
| echo -e "${DIM} adb shell getconf PAGE_SIZE # Should return: 16384${ENDCOLOR}" | |
| echo | |
| echo -e "${DIM} # Verify APK alignment${ENDCOLOR}" | |
| echo -e "${DIM} zipalign -c -P 16 -v 4 app-release.apk${ENDCOLOR}" | |
| print_summary_box "CONGRATULATIONS!" "success" \ | |
| "${PARTY} Your app is 16KB page size compatible!" \ | |
| "" \ | |
| "${CHECK_MARK} All native libraries meet Google Play requirements" \ | |
| "${CHECK_MARK} Ready for devices with 16KB page sizes" \ | |
| "${CHECK_MARK} Compliant with November 1st, 2025 deadline" \ | |
| "" \ | |
| "Recommendation: Test thoroughly on 16KB environment to ensure" \ | |
| "no runtime issues exist in your application code." | |
| fi | |
| echo | |
| print_status "info" "Analysis completed at $(date)" | |
| echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment