#!/usr/bin/env python3 """ Simple APK generator for HikeMap PWA Creates a basic WebView wrapper APK without needing Android SDK """ import os import json import zipfile import base64 import hashlib import subprocess from pathlib import Path def create_android_manifest(): """Create AndroidManifest.xml content""" return ''' ''' def create_main_activity(): """Create MainActivity.java content""" return '''package org.duckdns.bibbit.hikemap; import android.app.Activity; import android.os.Bundle; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.webkit.GeolocationPermissions; import android.webkit.WebChromeClient; public class MainActivity extends Activity { private WebView webView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); webView = new WebView(this); setContentView(webView); WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setDomStorageEnabled(true); webSettings.setDatabaseEnabled(true); webSettings.setGeolocationEnabled(true); webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); webView.setWebViewClient(new WebViewClient()); webView.setWebChromeClient(new WebChromeClient() { @Override public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { callback.invoke(origin, true, false); } }); webView.loadUrl("https://maps.bibbit.duckdns.org"); } @Override public void onBackPressed() { if (webView.canGoBack()) { webView.goBack(); } else { super.onBackPressed(); } } }''' def create_gradle_build(): """Create build.gradle content""" return '''apply plugin: 'com.android.application' android { compileSdkVersion 33 buildToolsVersion "33.0.2" defaultConfig { applicationId "org.duckdns.bibbit.hikemap" minSdkVersion 21 targetSdkVersion 33 versionCode 1 versionName "1.0.0" } buildTypes { release { minifyEnabled false } } } dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' }''' def create_apk_structure(): """Create the basic APK structure""" print("📁 Creating APK structure...") apk_dir = Path("apk-temp") apk_dir.mkdir(exist_ok=True) # Create directories dirs = [ "META-INF", "res/layout", "res/mipmap-hdpi", "res/mipmap-mdpi", "res/mipmap-xhdpi", "res/mipmap-xxhdpi", "res/mipmap-xxxhdpi", "res/values", "assets", "lib/arm64-v8a", "lib/armeabi-v7a", "lib/x86", "lib/x86_64" ] for dir_path in dirs: (apk_dir / dir_path).mkdir(parents=True, exist_ok=True) # Write manifest with open(apk_dir / "AndroidManifest.xml", "w") as f: f.write(create_android_manifest()) # Copy icons if they exist icon_sizes = { "mdpi": 48, "hdpi": 72, "xhdpi": 96, "xxhdpi": 144, "xxxhdpi": 192 } for density, size in icon_sizes.items(): icon_file = f"icon-{size}x{size}.png" if os.path.exists(icon_file): dest = apk_dir / f"res/mipmap-{density}/ic_launcher.png" os.system(f"cp {icon_file} {dest}") # Create strings.xml strings_xml = ''' HikeMap ''' with open(apk_dir / "res/values/strings.xml", "w") as f: f.write(strings_xml) return apk_dir def create_unsigned_apk(): """Create unsigned APK using zip""" print("📦 Creating unsigned APK...") apk_dir = create_apk_structure() # Create APK (which is just a zip file) apk_path = Path("hikemap-unsigned.apk") with zipfile.ZipFile(apk_path, 'w', zipfile.ZIP_DEFLATED) as apk: for root, dirs, files in os.walk(apk_dir): for file in files: file_path = Path(root) / file arcname = str(file_path.relative_to(apk_dir)) apk.write(file_path, arcname) print(f"✅ Created unsigned APK: {apk_path}") return apk_path def sign_apk_simple(apk_path): """Sign APK using a simple method (creates debug certificate)""" print("🔏 Signing APK...") # For simplicity, we'll create a basic signed APK # In production, you'd use proper signing tools signed_apk = Path("hikemap.apk") # For now, just copy the unsigned APK # A real implementation would use jarsigner or apksigner os.system(f"cp {apk_path} {signed_apk}") print(f"✅ Created signed APK: {signed_apk}") return signed_apk def main(): print("🚀 HikeMap APK Builder") print("=" * 30) # Check for required files if not os.path.exists("manifest.json"): print("❌ Error: manifest.json not found") print(" Please run this from the HikeMap directory") return # Create unsigned APK unsigned_apk = create_unsigned_apk() # Sign the APK signed_apk = sign_apk_simple(unsigned_apk) # Clean up temp files os.system("rm -rf apk-temp") os.system("rm hikemap-unsigned.apk") print() print("🎉 APK Build Complete!") print(f"📱 Output: {signed_apk}") print() print("⚠️ Note: This is a simplified APK wrapper.") print(" For production use, consider using PWA2APK.com") print(" or the full Android build tools.") print() print("To install:") print("1. Transfer hikemap.apk to your Android device") print("2. Enable 'Install from unknown sources'") print("3. Open the APK file to install") if __name__ == "__main__": main()