Skip to content

Repository files navigation

Skywriter

A beautiful Android app for writing character NFC data to physical tags

Android Kotlin Material Design 3

Skywriter is a modern Android application that allows you to browse characters organized by game series, select them visually, and write their NFC data to physical tags using your Android device's NFC capabilities. The app supports multiple tag types including Mifare Classic 1K and NTAG215 tags.

✨ Features

Core Functionality

  • πŸ“± Dual Mode Support: Choose between different character databases and tag types
  • 🏠 Home Screen: Intuitive mode selection to switch between character types
  • πŸ“‹ Browse Characters: View all characters organized by game series with collapsible headers
  • πŸ” Smart Search: Fast partial matching search to quickly find specific characters
  • πŸ“ Character Details: View detailed information including biography, abilities, and element types
  • πŸ’Ύ NFC Writing: Write character data to compatible NFC tags with full verification
  • βœ… Tag Compatibility Checker: Comprehensive tool that automatically detects tag type and verifies compatibility
  • 🧹 Tag Eraser: Clear tags to a known blank state before writing
  • πŸ” Automatic Authentication: Extracts and uses authentication keys from source data
  • πŸ“Š Real-time Feedback: Progress indicators and detailed status messages
  • βœ“ Write Verification: Reads back written data to ensure successful writes

User Experience

  • 🎨 Beautiful UI: Clean white background with navy blue accents (Material Design 3)
  • πŸ“± Modern Design: Collapsible game sections, intuitive navigation, and smooth animations
  • πŸ›‘οΈ Safety First: User-initiated actions only - tap buttons before any NFC operations
  • ⚠️ Smart Warnings: Compatibility checker warns about potential issues before writing
  • πŸ”„ Error Handling: Graceful handling of locked tags, authentication failures, and incompatible tags
  • πŸ“± Persistent Header: Logo and menu accessible from all screens
  • 🏠 Quick Navigation: Logo click returns to home screen

Technical Excellence

  • πŸ—οΈ MVVM Architecture: Clean separation of concerns with ViewModels and LiveData
  • πŸ§ͺ Comprehensive Testing: Unit tests, instrumented tests, and E2E test coverage
  • πŸ“¦ Portal Compatible: Writes ALL blocks including sector trailers for full compatibility
  • πŸ”‘ Key Extraction: Automatically extracts authentication keys from source data
  • πŸ“± Multi-density Support: Optimized icons and resources for all screen densities
  • πŸ”‹ Power Management: Keeps screen on during NFC operations to prevent interruptions
  • πŸ”Œ Connection Management: Automatic reconnection handling for stable NFC operations

🎨 Design

Skywriter features a clean, modern design with:

  • White Background: Easy on the eyes, professional appearance
  • Navy Blue Accents: Primary color (#001F3F) for buttons, headers, and highlights
  • Material Design 3: Latest Material Design components and patterns
  • Custom Branding: Skywriter logo in app icon and header
  • No Drop Shadows: Flat design with clean edges

πŸ“Έ Screenshots

Screenshots coming soon

πŸš€ Quick Start

Prerequisites

  • Android Device: Android 7.0 (API 24) or higher with NFC support
  • NFC Tags:
    • Mifare Classic 1K compatible tags (for character mode)
    • NTAG215 tags (for compatible tag mode)
  • Android Studio: Latest version recommended (for development)

Installation

  1. Clone the repository:

    git clone https://github.com/BitcoinErrorLog/skywriter.git
    cd skywriter
  2. Prepare Character Data:

    • Character JSON files should be in app/src/main/assets/Android_NFC_Data/
    • Compatible tag JSON files should be in app/src/main/assets/Amiibo_NFC_Data/
    • The app will automatically load all characters on first launch
  3. Build the APK:

    ./gradlew assembleDebug

    The APK will be in app/build/outputs/apk/debug/skywriter.apk

  4. Install on Device:

    • Transfer the APK to your Android device
    • Enable "Install from Unknown Sources" if needed
    • Install and launch the app

πŸ“– Usage Guide

Getting Started

  1. Launch the app - You'll see the home screen with mode selection
  2. Choose a Mode:
    • Character Mode: For writing character data to Mifare Classic tags
    • Compatible Tag Mode: For writing compatible tag data to NTAG215 tags
  3. Navigate: Use the logo to return home, or the menu button for quick access

Browsing Characters

  1. Select Mode - Choose your desired mode from the home screen
  2. Browse - View all characters organized by game series
  3. Expand/Collapse Games - Tap game headers to expand or collapse character lists
  4. Search - Tap the search FAB to quickly find specific characters by name
  5. View Details - Tap any character card to see detailed information including biography and abilities

Writing to NFC Tags

  1. Select a Character:

    • Browse or search to find your desired character
    • Tap the character card to open details
  2. Start Write Process:

    • Tap "Write to Tag" in the character details dialog
    • You'll be taken to the write screen
  3. Initiate Write:

    • Tap the "Write" button (user action required)
    • The app will automatically check tag compatibility when tag is detected
    • Compatibility check runs automatically - no need to tap again
  4. Compatibility Check:

    • βœ… Compatible: Writing begins automatically
    • ⚠️ Warning: You can choose to write anyway or cancel
    • ❌ Incompatible: Detailed error message with recommendations
  5. Wait for Completion:

    • Watch the progress indicator
    • The app verifies writes by reading back data
    • Success message appears when complete
    • Tag is ready to use

Checking Tag Compatibility

  1. Open Tag Checker:

    • Tap the menu (three dots) in the toolbar
    • Select "Check Tag Compatibility"
  2. Check a Tag:

    • The checker automatically detects tag type (Mifare Classic or NTAG215)
    • Tap the "Check Tag" button (user action required)
    • Then tap your phone to the NFC tag
    • View detailed compatibility report
  3. Review Results:

    • See tag type, block/page count, authentication status
    • View tag contents and current data
    • Read issues and recommendations
    • Use "Check Again" to test another tag

Erasing Tags

  1. Open Tag Checker:

    • Navigate to the tag checker from the menu
  2. Check Tag First:

    • Check the tag to see its current state
  3. Erase Tag:

    • Tap "Erase Tag" button
    • Confirm the erase operation
    • Tag will be cleared to a blank state
    • Verification ensures data was actually erased

πŸ”§ Technical Details

App Information

  • Package Name: com.bitcoinerrorlog.skywriter
  • Min SDK: 24 (Android 7.0 Nougat)
  • Target SDK: 34 (Android 14)
  • Compile SDK: 34
  • Build Tools: Latest Android Gradle Plugin
  • Language: Kotlin 100%

NFC Support

Mifare Classic 1K Tags:

  • Tag Type: Mifare Classic 1K (64 blocks, 16 sectors)
  • Authentication: Automatic key extraction from source data
  • Block Writing: All 64 blocks including sector trailers
  • UID Handling: Graceful handling of locked UID blocks
  • Verification: Reads back critical blocks to verify writes

NTAG215 Tags:

  • Tag Type: NTAG215 (135 pages, 540 bytes)
  • Page-based Writing: Writes all 135 pages including UID pages
  • Compatibility Check: Verifies ATQA/SAK and read/write capability
  • Write Verification: Reads back critical pages to ensure data was written
  • Erase Support: Can erase all data pages to blank state

Architecture

  • Pattern: MVVM (Model-View-ViewModel)
  • UI: Material Design 3 Components
  • Navigation: AndroidX Navigation Component
  • Async: Kotlin Coroutines
  • State: LiveData and ViewModel
  • Database: JSON-based asset loading (no SQLite)

🎯 Portal Compatibility

Why It Matters

Portal devices require complete and accurate NFC data to recognize characters. This app ensures full compatibility by:

βœ… What the App Does

For Mifare Classic Tags:

  • Writes ALL Blocks: Including sector trailers (blocks 3, 7, 11, 15, etc.)
  • Extracts Keys: Automatically extracts Key A and Key B from source data
  • Proper Authentication: Uses extracted keys for sector authentication
  • Complete Data: All 64 blocks written in correct order
  • Error Handling: Continues writing even if Block 0 (UID) is locked
  • Write Verification: Verifies critical blocks were written correctly

For NTAG215 Tags:

  • Writes ALL Pages: All 135 pages including UID pages (if not locked)
  • Compatibility Check: Verifies tag is genuine NTAG215 before writing
  • Write Verification: Reads back critical pages to ensure data persistence
  • Erase Support: Can clear tags to blank state for fresh writes

πŸ”‘ Authentication Keys

Mifare Classic: The app extracts authentication keys from the sector trailer blocks in your source data:

  • Reads Key A (bytes 0-5) and Key B (bytes 10-15) from each sector trailer
  • Uses these keys for authentication before writing each sector
  • Falls back to default keys if extraction fails

NTAG215:

  • No authentication required (uses NfcA technology)
  • Verifies tag type using ATQA and SAK values
  • Checks read/write capability before writing

πŸ“‹ Testing with Portal

To verify compatibility:

  1. Write a character to a compatible tag
  2. Use the tag checker to verify the write was successful
  3. Place the tag on the portal device
  4. The portal should recognize the character

⚠️ UID Limitations

Important: Most standard NFC tags have locked UIDs that cannot be changed. This is normal and expected:

  • βœ… Character data in data blocks/pages is what the portal primarily reads
  • βœ… The app handles locked UIDs gracefully
  • βœ… Write verification ensures data was written even if UID is locked
  • ⚠️ For 100% compatibility, you may need UID-changeable tags

πŸ§ͺ Testing

Running Tests

Unit Tests (run on JVM):

./gradlew test

Instrumented Tests (run on device/emulator):

./gradlew connectedAndroidTest

All Tests:

./gradlew test connectedAndroidTest

Test Coverage

  • βœ… Unit Tests: Data models, NFC writer utilities, erase operations, WriteResult types
  • βœ… Instrumented Tests: Database operations, NFC manager functionality, UI navigation
  • βœ… E2E Tests: Simulated NFC write flow

Note: Unit tests for NFC operations are limited because Android framework classes cannot be mocked. For comprehensive NFC testing, use instrumented tests with actual hardware or manual testing.

See TESTING_NFC.md and RUN_TESTS.md for detailed testing documentation.

πŸ› οΈ Development

Building the Project

# Build debug APK (automatically copies to root as skywriter.apk)
./gradlew assembleDebug

# Build release APK (automatically copies to root as skywriter.apk)
./gradlew assembleRelease

# Manually copy APK to root (if needed)
./gradlew copyApkToRoot

# Run lint checks
./gradlew lint

# Clean build
./gradlew clean

Note: The APK is automatically copied to the root directory (skywriter.apk) after each build. This makes it easy to find and share the latest build.

Project Structure

skywriter/
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ main/
β”‚   β”‚   β”‚   β”œβ”€β”€ java/...          # Kotlin source files
β”‚   β”‚   β”‚   β”œβ”€β”€ res/              # Resources (layouts, strings, icons)
β”‚   β”‚   β”‚   └── assets/           # JSON character data
β”‚   β”‚   β”œβ”€β”€ test/                 # Unit tests
β”‚   β”‚   └── androidTest/          # Instrumented tests
β”‚   └── build.gradle.kts          # App-level build config
β”œβ”€β”€ gradle/                        # Gradle wrapper
β”œβ”€β”€ archive/                       # Archived files (gitignored)
└── README.md                      # This file

Key Components

Data Layer:

  • CharacterModel: Parcelable data class representing a character
  • AmiiboModel: Data class for compatible tag data
  • NFCDatabase: JSON file parsing and character loading
  • AmiiboDatabase: JSON file parsing for compatible tag data
  • CharacterRepository: Data access abstraction
  • AmiiboRepository: Data access for compatible tags

NFC Layer:

  • MifareClassicWriter: Core NFC writing logic with authentication
  • NTAG215Writer: Writing logic for NTAG215 tags
  • NFCManager: NFC adapter and tag detection management
  • TagCompatibilityChecker: Detailed tag compatibility analysis for Mifare Classic
  • NTAG215CompatibilityChecker: Compatibility checking for NTAG215 tags
  • TagEraser: Erase functionality for Mifare Classic tags
  • AmiiboTagEraser: Erase functionality for NTAG215 tags
  • TagReader: Read tag contents and identify characters
  • AmiiboTagReader: Read NTAG215 tag contents
  • WriteResult: Sealed class for operation results

UI Layer:

  • MainActivity: Host activity with navigation and NFC handling
  • HomeFragment: Mode selection screen
  • CharacterListFragment: Character browsing with search
  • AmiiboListFragment: Compatible tag browsing with search
  • CharacterDetailDialog: Character information display
  • AmiiboDetailDialog: Compatible tag information display
  • WriteNFCFragment: NFC writing interface for characters
  • WriteAmiiboFragment: NFC writing interface for compatible tags
  • TagCheckFragment: Standalone tag compatibility checker with erase

ViewModel:

  • CharacterViewModel: State management for character list and search
  • AmiiboViewModel: State management for compatible tag list and search

Dependencies

Core Android:

  • AndroidX Core KTX
  • AppCompat
  • Material Design Components 3
  • Constraint Layout

Architecture:

  • Lifecycle (ViewModel, LiveData)
  • Navigation Component
  • Kotlin Coroutines

Testing:

  • JUnit 4
  • Mockito
  • AndroidX Test
  • Espresso

πŸ› Troubleshooting

NFC Not Available

  • βœ… Ensure NFC is enabled in device settings
  • βœ… Check that device supports the required tag type
  • βœ… Verify NFC permissions in app settings
  • βœ… Some devices require NFC to be enabled in quick settings

Write Failures

  • βœ… Tag may be locked or use non-default keys (app handles this automatically)
  • βœ… Tag may not be compatible (use tag checker first)
  • βœ… Ensure tag is properly positioned during write (keep steady)
  • βœ… Try a different tag if issues persist
  • βœ… Check that write verification passed (app verifies writes automatically)

No Characters Displayed

  • βœ… Verify JSON files are in the correct assets directory
  • βœ… Check JSON file format matches expected structure
  • βœ… Review logcat for parsing errors: adb logcat | grep Skywriter
  • βœ… Ensure files are properly formatted JSON (not corrupted)

Tag Compatibility Issues

  • βœ… Use the tag checker before writing to verify compatibility
  • βœ… Ensure tag matches the selected mode (Mifare Classic or NTAG215)
  • βœ… Check that tag is not write-protected
  • βœ… Some tags may require specific authentication keys
  • βœ… Verify tag type is correctly detected by the checker

Build Issues

  • βœ… Ensure you have JDK 17 or higher installed
  • βœ… Check that Android SDK is properly configured
  • βœ… Try ./gradlew clean then rebuild
  • βœ… See DEBUGGING.md for debugging tips

πŸ“š Documentation

🀝 Contributing

We welcome contributions! Here's how:

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Add tests for new functionality
  5. Run tests: ./gradlew test connectedAndroidTest
  6. Commit your changes: git commit -m 'Add amazing feature'
  7. Push to branch: git push origin feature/amazing-feature
  8. Open a Pull Request

Code Style

  • Follow Kotlin coding conventions
  • Use meaningful variable and function names
  • Add comments for complex logic
  • Write tests for new features

πŸ“ License

[Add your license here]

πŸ™ Acknowledgments

  • Built with ❀️ using Kotlin and Material Design 3
  • NFC data format based on Flipper Zero .nfc file structure
  • Designed for compatibility with portal devices

πŸ“ž Support

For issues, questions, or contributions:

  • Open an issue on GitHub
  • Check existing documentation
  • Review troubleshooting section above

Made with ❀️ for the NFC community

⭐ Star this repo if you find it useful!

About

Make custom NFC tags for your portal.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages