Android 13 Framework Patcher #51
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
| name: Android 13 Framework Patcher | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| api_level: | |
| description: 'Android API level (Android 13 is API 33)' | |
| required: true | |
| default: '33' | |
| type: string | |
| device_codename: | |
| description: 'Device codename (for zip file naming, e.g., "munch"). Optional, will use sanitized device_name if not provided.' | |
| required: false | |
| type: string | |
| device_name: | |
| description: 'Full device name (for release description, e.g., "Redmi Note 11T Pro")' | |
| required: true | |
| type: string | |
| version_name: | |
| description: 'ROM/firmware version identifier' | |
| required: true | |
| type: string | |
| framework_url: | |
| description: 'URL to framework.jar' | |
| required: true | |
| type: string | |
| services_url: | |
| description: 'URL to services.jar' | |
| required: true | |
| type: string | |
| miui_services_url: | |
| description: 'URL to miui-services.jar' | |
| required: false | |
| type: string | |
| miui_framework_url: | |
| description: 'URL to miui-framework.jar (required for: add_gboard)' | |
| required: false | |
| type: string | |
| user_id: | |
| description: 'Telegram User ID to notify (optional)' | |
| required: false | |
| type: string | |
| features: | |
| description: 'Comma-separated list of features to enable (e.g., "disable_signature_verification,kaorios_toolbox")' | |
| required: false | |
| type: string | |
| default: 'disable_signature_verification' | |
| jobs: | |
| patch: | |
| name: Android 13 Framework Patcher | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y p7zip-full wget zip python3 python3-pip | |
| pip3 install gdown | |
| - name: Prepare tools directory | |
| run: | | |
| mkdir -p tools | |
| if [ ! -f tools/apktool.jar ]; then | |
| wget -O tools/apktool.jar https://github.com/iBotPeaches/Apktool/releases/download/v2.9.3/apktool_2.9.3.jar | |
| fi | |
| - name: Download framework JARs | |
| run: | | |
| # Smart download function that handles Google Drive links | |
| download_file() { | |
| url=$1 | |
| output=$2 | |
| echo "Downloading $output from $url" | |
| if echo "$url" | grep -q "drive.google.com"; then | |
| echo "Detected Google Drive link, using gdown..." | |
| gdown --fuzzy -O "$output" "$url" | |
| else | |
| echo "Using wget for download..." | |
| wget -O "$output" "$url" | |
| fi | |
| } | |
| # Determine which JARs are needed based on features | |
| FEATURES="${{ github.event.inputs.features }}" | |
| NEED_FRAMEWORK=0 | |
| NEED_SERVICES=0 | |
| NEED_MIUI_SERVICES=0 | |
| NEED_MIUI_FRAMEWORK=0 | |
| # Signature verification needs all 3 | |
| if [[ "$FEATURES" == *"disable_signature_verification"* ]]; then | |
| NEED_FRAMEWORK=1 | |
| NEED_SERVICES=1 | |
| NEED_MIUI_SERVICES=1 | |
| fi | |
| # Kaorios toolbox only needs framework.jar | |
| if [[ "$FEATURES" == *"kaorios_toolbox"* ]]; then | |
| NEED_FRAMEWORK=1 | |
| fi | |
| # Add Gboard needs miui-services.jar and miui-framework.jar | |
| if [[ "$FEATURES" == *"add_gboard"* ]]; then | |
| NEED_MIUI_SERVICES=1 | |
| NEED_MIUI_FRAMEWORK=1 | |
| fi | |
| # Default to signature verification if no feature specified | |
| if [ $NEED_FRAMEWORK -eq 0 ] && [ $NEED_SERVICES -eq 0 ] && [ $NEED_MIUI_SERVICES -eq 0 ]; then | |
| NEED_FRAMEWORK=1 | |
| NEED_SERVICES=1 | |
| NEED_MIUI_SERVICES=1 | |
| fi | |
| echo "============================================" | |
| echo "Feature-based JAR requirements:" | |
| echo " framework.jar: $([ $NEED_FRAMEWORK -eq 1 ] && echo 'REQUIRED' || echo 'not needed')" | |
| echo " services.jar: $([ $NEED_SERVICES -eq 1 ] && echo 'REQUIRED' || echo 'not needed')" | |
| echo " miui-services.jar: $([ $NEED_MIUI_SERVICES -eq 1 ] && echo 'REQUIRED' || echo 'not needed')" | |
| echo " miui-framework.jar: $([ $NEED_MIUI_FRAMEWORK -eq 1 ] && echo 'REQUIRED' || echo 'not needed')" | |
| echo "============================================" | |
| # Download required JARs | |
| if [ $NEED_FRAMEWORK -eq 1 ]; then | |
| if [ -z "${{ github.event.inputs.framework_url }}" ]; then | |
| echo "❌ framework.jar URL is required but not provided!" | |
| exit 1 | |
| fi | |
| download_file "${{ github.event.inputs.framework_url }}" "framework.jar" | |
| fi | |
| if [ $NEED_SERVICES -eq 1 ]; then | |
| if [ -z "${{ github.event.inputs.services_url }}" ]; then | |
| echo "❌ services.jar URL is required but not provided!" | |
| exit 1 | |
| fi | |
| download_file "${{ github.event.inputs.services_url }}" "services.jar" | |
| fi | |
| if [ $NEED_MIUI_SERVICES -eq 1 ]; then | |
| if [ -z "${{ github.event.inputs.miui_services_url }}" ]; then | |
| echo "❌ miui-services.jar URL is required but not provided!" | |
| exit 1 | |
| fi | |
| download_file "${{ github.event.inputs.miui_services_url }}" "miui-services.jar" | |
| fi | |
| if [ $NEED_MIUI_FRAMEWORK -eq 1 ]; then | |
| if [ -z "${{ github.event.inputs.miui_framework_url }}" ]; then | |
| echo "❌ miui-framework.jar URL is required but not provided!" | |
| exit 1 | |
| fi | |
| download_file "${{ github.event.inputs.miui_framework_url }}" "miui-framework.jar" | |
| fi | |
| echo "Validating downloaded JAR files..." | |
| for jar in framework.jar services.jar miui-services.jar miui-framework.jar; do | |
| if [ -f "$jar" ]; then | |
| file_size=$(stat -c%s "$jar") | |
| echo "Checking $jar (${file_size} bytes)..." | |
| if [ $file_size -lt 1500000 ]; then | |
| echo "❌ Error: $jar is too small (${file_size} bytes). Download might have failed." | |
| exit 1 | |
| fi | |
| echo "✅ $jar validated successfully" | |
| fi | |
| done | |
| echo "All required JAR files downloaded and validated!" | |
| - name: Set safe device codename | |
| id: set_codename | |
| run: | | |
| RAW_CODENAME="${{ github.event.inputs.device_codename }}" | |
| if [ -z "$RAW_CODENAME" ]; then | |
| RAW_CODENAME="${{ github.event.inputs.device_name }}" | |
| fi | |
| # Sanitize: Remove spaces and other invalid tag characters | |
| SAFE_CODENAME=$(echo "$RAW_CODENAME" | sed 's/[^a-zA-Z0-9._-]/_/g') | |
| echo "codename=${SAFE_CODENAME}" >> $GITHUB_OUTPUT | |
| - name: Run Android 13 patcher | |
| run: | | |
| chmod +x scripts/patcher_a13.sh | |
| # Build feature flags | |
| FEATURE_FLAGS="" | |
| if [[ "${{ github.event.inputs.features }}" == *disable_signature_verification* ]]; then | |
| FEATURE_FLAGS="$FEATURE_FLAGS --disable-signature-verification" | |
| fi | |
| # If no features selected, default to signature bypass | |
| if [ -z "$FEATURE_FLAGS" ]; then | |
| FEATURE_FLAGS="--disable-signature-verification" | |
| fi | |
| if [[ "${{ github.event.inputs.features }}" == *kaorios_toolbox* ]]; then | |
| FEATURE_FLAGS="$FEATURE_FLAGS --kaorios-toolbox" | |
| fi | |
| if [[ "${{ github.event.inputs.features }}" == *add_gboard* ]]; then | |
| FEATURE_FLAGS="$FEATURE_FLAGS --add-gboard" | |
| fi | |
| # Build JAR flags based on which JARs are present | |
| JAR_FLAGS="" | |
| if [ -f "framework.jar" ]; then | |
| JAR_FLAGS="$JAR_FLAGS --framework" | |
| fi | |
| if [ -f "services.jar" ]; then | |
| JAR_FLAGS="$JAR_FLAGS --services" | |
| fi | |
| if [ -f "miui-services.jar" ]; then | |
| JAR_FLAGS="$JAR_FLAGS --miui-services" | |
| fi | |
| if [ -f "miui-framework.jar" ]; then | |
| JAR_FLAGS="$JAR_FLAGS --miui-framework" | |
| fi | |
| echo "Running patcher with JAR flags: $JAR_FLAGS" | |
| echo "Feature flags: $FEATURE_FLAGS" | |
| ./scripts/patcher_a13.sh \ | |
| "${{ github.event.inputs.api_level }}" \ | |
| "${{ steps.set_codename.outputs.codename }}" \ | |
| "${{ github.event.inputs.version_name }}" \ | |
| $JAR_FLAGS $FEATURE_FLAGS | |
| - name: Verify module creation | |
| run: | | |
| echo "Checking if module was created properly..." | |
| MODULE_FILE=$(ls Framework-Patcher-${{ steps.set_codename.outputs.codename }}*.zip 2>/dev/null || echo "") | |
| if [ -z "$MODULE_FILE" ]; then | |
| echo "❌ No module ZIP found!" | |
| exit 1 | |
| fi | |
| echo "✅ Module ZIP found: $MODULE_FILE" | |
| echo "Module contents:" | |
| unzip -l "$MODULE_FILE" | head -20 | |
| echo "Checking for MMT-Extended files:" | |
| unzip -l "$MODULE_FILE" | grep -E "(module\.prop|customize\.sh|common/functions\.sh|META-INF)" || echo "❌ Missing MMT-Extended files" | |
| - name: Set Release Info | |
| id: release_info | |
| run: | | |
| # Format version name to be git tag friendly | |
| SAFE_VERSION=$(echo "${{ github.event.inputs.version_name }}" | sed 's/[^a-zA-Z0-9._-]/_/g') | |
| # Add timestamp to ensure unique tags | |
| TIMESTAMP=$(date +'%Y%m%d-%H%M%S') | |
| RELEASE_TAG="${{ steps.set_codename.outputs.codename }}_${SAFE_VERSION}_${TIMESTAMP}" | |
| echo "tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT | |
| echo "name=Android 13 Framework Patch for ${{ github.event.inputs.device_name }} (${{ github.event.inputs.version_name }})" >> $GITHUB_OUTPUT | |
| - name: Find Module ZIP | |
| id: find_zip | |
| run: | | |
| # Find the module ZIP | |
| ZIP_FILE=$(ls Framework-Patcher-${{ steps.set_codename.outputs.codename }}*.zip 2>/dev/null || echo "") | |
| if [ -z "$ZIP_FILE" ]; then | |
| echo "No module ZIP found!" | |
| exit 1 | |
| fi | |
| echo "file_path=${ZIP_FILE}" >> $GITHUB_OUTPUT | |
| - name: Delete Existing Release | |
| uses: actions/github-script@v6 | |
| continue-on-error: true | |
| with: | |
| script: | | |
| try { | |
| const releases = await github.rest.repos.listReleases({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo | |
| }); | |
| const existingRelease = releases.data.find(r => r.tag_name === '${{ steps.release_info.outputs.tag }}'); | |
| if (existingRelease) { | |
| console.log('Found existing release, deleting...'); | |
| await github.rest.repos.deleteRelease({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| release_id: existingRelease.id | |
| }); | |
| // Delete the tag | |
| try { | |
| await github.rest.git.deleteRef({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: 'tags/' + '${{ steps.release_info.outputs.tag }}' | |
| }); | |
| } catch (e) { | |
| console.log('Tag might not exist, continuing...'); | |
| } | |
| } | |
| } catch (e) { | |
| console.log('No existing release found or error occurred:', e.message); | |
| } | |
| - name: Generate Release Body | |
| id: generate_release_body | |
| env: | |
| DEVICE_NAME: ${{ github.event.inputs.device_name }} | |
| VERSION_NAME: ${{ github.event.inputs.version_name }} | |
| API_LEVEL: ${{ github.event.inputs.api_level }} | |
| FRAMEWORK_URL: ${{ github.event.inputs.framework_url }} | |
| SERVICES_URL: ${{ github.event.inputs.services_url }} | |
| MIUI_SERVICES_URL: ${{ github.event.inputs.miui_services_url }} | |
| REPO: ${{ github.repository }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| # Build features list | |
| FEATURES_LIST=() | |
| if [[ "${{ github.event.inputs.features }}" == *kaorios_toolbox* ]]; then | |
| FEATURES_LIST+=("- Kaorios Toolbox (Play Integrity Fix)") | |
| fi | |
| if [[ "${{ github.event.inputs.features }}" == *add_gboard* ]]; then | |
| FEATURES_LIST+=("- Add Gboard Support") | |
| fi | |
| if [ ${#FEATURES_LIST[@]} -eq 0 ]; then | |
| if [ ${#FEATURES_LIST[@]} -eq 0 ]; then | |
| FEATURES="- Signature Verification Bypass (default)" | |
| else | |
| FEATURES=$(printf '%s\n' "${FEATURES_LIST[@]}") | |
| fi | |
| # Create release body | |
| cat > /tmp/release_body.md << RELEASE_EOF | |
| Android 13 Framework Patcher for $DEVICE_NAME | |
| Device: $DEVICE_NAME | |
| Version: $VERSION_NAME | |
| Android API: $API_LEVEL | |
| Important: This module is built specifically for $DEVICE_NAME running $VERSION_NAME. Installing on other devices or ROM versions may cause boot loops or system issues. | |
| Compatible with Magisk, KernelSU, and SUFS | |
| Features: | |
| FEATURES_PLACEHOLDER | |
| Source files: | |
| - Framework: $FRAMEWORK_URL | |
| - Services: $SERVICES_URL | |
| - MIUI Services: $MIUI_SERVICES_URL | |
| Built: $(date +'%Y-%m-%d %H:%M:%S UTC') | |
| Workflow: https://github.com/$REPO/actions/runs/$RUN_ID | |
| Changelog: https://github.com/$REPO/blob/master/CHANGELOG.md | |
| RELEASE_EOF | |
| # Replace features placeholder with actual features (handle multiline properly) | |
| # Create temporary file with features | |
| echo "$FEATURES" > /tmp/features.txt | |
| # Use awk to replace placeholder with file content | |
| awk '{ | |
| if ($0 ~ /FEATURES_PLACEHOLDER/) { | |
| while ((getline line < "/tmp/features.txt") > 0) print line | |
| close("/tmp/features.txt") | |
| } else { | |
| print $0 | |
| } | |
| }' /tmp/release_body.md > /tmp/release_body_final.md | |
| mv /tmp/release_body_final.md /tmp/release_body.md | |
| # Output to GitHub | |
| echo "release_body<<EOF" >> $GITHUB_OUTPUT | |
| cat /tmp/release_body.md >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Create Release | |
| id: create_release | |
| uses: softprops/action-gh-release@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| with: | |
| tag_name: ${{ steps.release_info.outputs.tag }} | |
| name: ${{ steps.release_info.outputs.name }} | |
| files: ${{ steps.find_zip.outputs.file_path }} | |
| body: | | |
| ${{ steps.generate_release_body.outputs.release_body }} | |
| - name: Upload patched jars | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android13-patched-jars-${{ github.run_id }} | |
| if-no-files-found: warn | |
| path: | | |
| framework_patched.jar | |
| services_patched.jar | |
| miui-services_patched.jar | |
| miui-framework_patched.jar | |
| retention-days: 7 | |
| - name: Upload module zip | |
| if: success() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: android13-module-${{ github.run_id }} | |
| if-no-files-found: warn | |
| path: Framework-Patcher-${{ steps.set_codename.outputs.codename }}*.zip | |
| retention-days: 7 | |
| - name: Send Telegram Notification (Success) | |
| if: success() && github.event.inputs.user_id != '' | |
| run: | | |
| escape_mdv2() { | |
| echo "$1" | sed -e 's/\\/\\\\/g' -e 's/\./\\./g' -e 's/\-/\\-/g' -e 's/!/\\!/g' -e 's/#/\\#/g' -e 's/{/\\{/g' -e 's/}/\\}/g' -e 's/(/\\(/g' -e 's/)/\\)/g' | |
| } | |
| DEVICE_CODENAME_ESCAPED=$(escape_mdv2 "${{ steps.set_codename.outputs.codename }}") | |
| DEVICE_NAME_ESCAPED=$(escape_mdv2 "${{ github.event.inputs.device_name }}") | |
| VERSION_NAME_ESCAPED=$(escape_mdv2 "${{ github.event.inputs.version_name }}") | |
| API_LEVEL_ESCAPED=$(escape_mdv2 "${{ github.event.inputs.api_level }}") | |
| MESSAGE=$(printf "Android 13 framework patch is ready for your device:\n\n> *Device:* \`%s\`\n> *Codename:* \`%s\`\n> *Version:* \`%s\`\n> *Android API:* \`%s\`\n\nModule compatible with Magisk, KSU, and SUFS" \ | |
| "$DEVICE_NAME_ESCAPED" \ | |
| "$DEVICE_CODENAME_ESCAPED" \ | |
| "$VERSION_NAME_ESCAPED" \ | |
| "$API_LEVEL_ESCAPED") | |
| RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${{ steps.release_info.outputs.tag }}" | |
| REPLY_MARKUP="{\"inline_keyboard\":[[{\"text\":\"Click here to download\",\"url\":\"$RELEASE_URL\"}],[{\"text\":\"Support me\",\"url\":\"https://buymeacoffee.com/jefino\"}]]}" | |
| curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \ | |
| -d chat_id=${{ github.event.inputs.user_id }} \ | |
| -d text="$MESSAGE" \ | |
| -d parse_mode="MarkdownV2" \ | |
| -d reply_markup="$REPLY_MARKUP" | |
| - name: Send Telegram Notification (Failure) | |
| if: failure() && github.event.inputs.user_id != '' | |
| run: | | |
| escape_mdv2() { | |
| echo "$1" | sed -e 's/\\/\\\\/g' -e 's/\./\\./g' -e 's/\-/\\-/g' -e 's/!/\\!/g' -e 's/#/\\#/g' -e 's/{/\\{/g' -e 's/}/\\}/g' -e 's/(/\\(/g' -e 's/)/\\)/g' | |
| } | |
| DEVICE_CODENAME_ESCAPED=$(escape_mdv2 "${{ steps.set_codename.outputs.codename }}") | |
| DEVICE_NAME_ESCAPED=$(escape_mdv2 "${{ github.event.inputs.device_name }}") | |
| VERSION_NAME_ESCAPED=$(escape_mdv2 "${{ github.event.inputs.version_name }}") | |
| WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" | |
| MESSAGE=$(printf "Android 13 framework patch failed for your device:\n\n> *Device:* \`%s\`\n> *Codename:* \`%s\`\n> *Version:* \`%s\`\n\nPlease check the workflow logs for more details." \ | |
| "$DEVICE_NAME_ESCAPED" \ | |
| "$DEVICE_CODENAME_ESCAPED" \ | |
| "$VERSION_NAME_ESCAPED") | |
| REPLY_MARKUP="{\"inline_keyboard\":[[{\"text\":\"View Workflow Run\",\"url\":\"$WORKFLOW_URL\"}]]}" | |
| curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \ | |
| -d chat_id=${{ github.event.inputs.user_id }} \ | |
| -d text="$MESSAGE" \ | |
| -d parse_mode="MarkdownV2" \ | |
| -d reply_markup="$REPLY_MARKUP" |