今日已更新 222 条资讯 | 累计 40667 条内容
关于我们

标签:#ios

找到 134 篇相关文章

AI 资讯

I Got Tired of Hand-Translating Xcode Plists, So I Built a Tiny Free Tool to Do It On-Device

If you've ever localized an iOS or macOS app, you know the drill: you've got a .plist file full of UI strings sitting in Base.lproj , and now you need the same file in fr.lproj , th.lproj , de.lproj ... and so on for every language you support. You can pay for a translation service, hand it to a freelancer, or sit there manually retyping strings into fifteen copies of the same file. I didn't want to do any of those things, so I spent a day building pListTranslatorApp — a small SwiftUI macOS app that opens an Xcode plist, finds the string values you want translated, batch-translates them using Apple's built-in Translation framework, and writes out a ready-to-use localized plist. It's free, it runs entirely on-device, and it's now sitting on GitHub for anyone who wants it. The constraint that shaped the whole thing I'm developing on a MacBook Air with a 256GB SSD and 8GB of RAM — not a lot of headroom. That ruled out a couple of obvious approaches: Cloud translation APIs (DeepL, Google Cloud Translate, etc.) work well, but even a generous free tier means an external dependency, an API key to manage, and a network round-trip for something that's ultimately just short UI strings. Downloading a pile of on-device language models "just in case" eats real disk space fast — Apple's Translation framework models are shared system-wide across apps, which helps, but they still add up if you're not paying attention. So the app leans entirely on Apple's Translation framework , downloading exactly one language pack at a time, on demand, and lets you delete it once you're done with that language. What it actually does Open a plist. Pick any Xcode .plist via a standard file importer. Choose which keys to translate. Originally I hardcoded it to look for a key called itemTitle , but that's obviously too narrow for anyone else's project — so it's now a comma-separated text field. Type itemTitle, title, label and it'll pick up all of them, anywhere in the plist's nested dictionaries and

2026-07-19 原文 →
AI 资讯

Part 2 — Search, palette, and settings

Part 2 — Search, palette, and settings Level: Intermediate · Time: ~35 minutes · Builds on: Part 1 — Contacts app Part 1 got you shipping. This one gets you productive . We'll take the Contacts app and give it the ergonomics real users expect: an adaptive sidebar that becomes a tab bar on iPhone, a command palette on ⌘K, honest loading states while data comes in, and a proper settings screen. Zero #if os guards. Zero re-rolled controls. What we're adding An adaptive shell — DFSidebar on regular width, DFTabBar on compact. A search field at the top of the list, filtering as you type. A ⌘K command palette exposing every action in the app. Skeleton loaders for a simulated slow fetch. A settings screen — notifications toggle, density picker, sync-interval slider, pinned-since date picker, beta-features checkbox. Per-component token overrides on the settings screen, without forking the theme. 1. Shell: sidebar on wide, tab bar on narrow The routing decision — sidebar vs tab bar — should be data, not a view hierarchy. Enumerate your sections once, then feed the two components the shapes they want. API note. DFSidebar uses Binding<String?> and is just the sidebar view — you compose the detail pane yourself (naturally via NavigationSplitView ). DFTabBar uses Binding<String> (non-optional) and does take a content builder that receives the selected ID. Both use plain String IDs, so we keep a simple Section enum and pass rawValue at the boundary. enum Section : String , CaseIterable , Identifiable , Hashable { case contacts , favorites , archive , settings var id : String { rawValue } var label : String { switch self { case . contacts : "Contacts" case . favorites : "Favorites" case . archive : "Archive" case . settings : "Settings" } } var icon : String { switch self { case . contacts : "person.2.fill" case . favorites : "star.fill" case . archive : "archivebox.fill" case . settings : "gear" } } static func from ( _ id : String ?) -> Section { id . flatMap ( Section . init (

2026-07-18 原文 →
AI 资讯

Every Third-Party iOS Keyboard Is a Graveyard. So I Built a Voice Keyboard From Scratch in C++.

If you've searched the App Store for a reliable third-party QWERTY keyboard on iOS, you know how that ends. Some are abandoned. Some are ad-riddled. Some feel like they were ported from Android and never touched again. The good ones are the ones that don't ship features so much as they don't crash. The system keyboard is fine. It's fine because Apple has been iterating on it for fifteen years. Nobody else has. Third-party keyboards on iOS are a graveyard. I'm building one that isn't. It's called Diction. Most people know it as a voice keyboard, and that's what I lead with, but under the hood it's a serious low-level QWERTY project too. This post is about that half of it, because that's the half nobody talks about. Why third-party QWERTY on iOS is a graveyard Building a good keyboard extension on iOS is hard. There's a strict memory ceiling. There's a permission dance the user has to opt into. There's no keychain access, no meaningful background work, and the extension can be killed the moment iOS decides it needs the RAM. Most keyboard makers ship a first version to check the box, then abandon it once they see how much work maintaining it takes. The result is what you see on the App Store today. Every third-party keyboard I've tried on iOS fails on at least one of these: Speed. You type a letter, the letter arrives. That's it. If there's a hitch you can feel, the keyboard is broken. Half the ones I've tried have a visible delay on every keystroke. Predictability. If you correct the same word back three times, that word should be yours. The keyboard should stop fighting you. Most never do. You fight the same wrong correction for a year. Recovery. iOS keyboard extensions are memory-constrained. Bad ones freeze under pressure. When you rapid-switch between apps, half the third-party keyboards on the store will lock up until you kill and reopen the host app. Autocorrect that isn't from 2014. Fix the obvious typos. Split words that ran together. Complete contractions. Ge

2026-07-15 原文 →
AI 资讯

How I export 1.2-gigapixel images on an iPhone without running out of memory

Rendering a big image on iOS is one of those things that looks trivial until your app gets killed by the OS mid-export. CGContext , draw, makeImage() , done — except the moment the output gets large, that innocent-looking pipeline quietly asks for gigabytes of RAM and iOS terminates you. I hit this wall building Mozary , an iOS app that packs 100+ photos into a single giant picture (a photo mosaic). In v1.1.0 I finally killed the "high-resolution export crashes with out-of-memory" bug for good. The fix: stop putting the canvas in RAM at all. Put it in a memory-mapped file and let the OS page it to disk. RAM usage dropped from "4.8 GB, please die" to a few dozen MB, flat, regardless of output size. This post is the walkthrough — with the actual Swift. If you've ever seen Core Graphics blow up on a big image (mosaics, collages, stitched panoramas, high-res rendering — same trap), this is for you. TL;DR A non-compressed bitmap costs 4 bytes/pixel . A 1.2-gigapixel image = ~4.8 GB of RAM just for the canvas. CGContext(data: nil, ...) allocates that in RAM. context.makeImage() then copies it again . Double death. Back the canvas with a memory-mapped file ( mmap ). Writes transparently page out to disk and don't count against your app's memory footprint . Wrap that same mapping in a CGImage via CGDataProvider — zero copy — and stream it straight to a JPEG on disk. Never call makeImage() . Decode source tiles at their draw size , not full size. Because you now spend disk instead of RAM: add a free-space pre-flight check and clean up temp files after a crash. Let's dig in. The problem: "compressed file size" is a lie about memory Mozary lays photos out on a grid. A typical high-res export is a 200 × 267 grid with each tile drawn at 150px : width: 200 × 150 = 30,000 px height: 267 × 150 = 40,050 px That's ~1.2 gigapixels . Here's the part people underestimate: the final JPEG is only a few hundred MB to ~2 GB because JPEG is compressed . But while you're drawing, the canvas i

2026-07-14 原文 →
AI 资讯

Apple’s public betas for iOS 27 and more are out now

Apple has just released public betas for iOS 27 and other major OS updates that are set to publicly launch this fall. The big new feature this year is Siri AI, the delayed AI-powered revamp to Siri. It actually works - which is big praise! - though it keeps things brief. Other betas available now […]

2026-07-14 原文 →
开发者

Commerce And Secrets Without An IAP Tax

Commerce is the easiest feature in this release to misunderstand, so the first sentence has to be blunt: What is Codename One? Codename One is an open-source framework for building native iOS, Android, desktop, and web apps from a single Java or Kotlin codebase. Learn more at codenameone.com . Commerce does not replace IAP and never will. Purchases still go through Apple, Google, or the payment processor you chose. Codename One does not process the payment, does not touch the money, and does not take a percentage. PR #5300 adds infrastructure around the annoying backend work that comes after a purchase: validation, entitlement checks, subscription lifecycle, webhooks, and reporting. That backend work is real. Anyone who has shipped subscriptions knows the trap. Buying a SKU is not the same as knowing whether the user has the right to a feature right now. Renewals, grace periods, refunds, billing retry, product changes, trials, family sharing and store server notifications all show up later. The device has one view. The store has another. Your backend usually needs a third. Commerce is the optional service that turns that mess into an entitlement. Entitlements Instead Of SKU Branches Your app should not need to know every SKU that grants pro . It should ask for pro . CommerceManager cm = CommerceManager . getInstance (); cm . setAppUserId ( accountId ); if ( cm . isEntitled ( "pro" )) { unlockProFeatures (); } Purchases are still delegated to the existing Purchase API: cm . subscribe ( "pro_monthly" ); // or cm . purchase ( "remove_ads" ); After a purchase, or when the app starts, refresh off the EDT: new Thread (() -> { CommerceManager cm = CommerceManager . getInstance (); cm . refresh (); CN . callSerially (() -> { if ( cm . isEntitled ( "pro" )) { unlockProFeatures (); } }); }). start (); refresh() validates the current receipts with the cloud when the build has a build_key and commerce is enabled. In a local build or simulator, it safely falls back to the normal

2026-07-13 原文 →
AI 资讯

Introducing App Store Release Agent – Automating my App Store Pipeline

Publishing ten apps in four months sounds good. And it is good. It means the bottleneck is no longer building the app. With AI-assisted coding, small utilities, focused experiments, and niche apps can go from idea to App Store submission in days, sometimes hours. But there is a second part that can soon get really ugly. And messy. And time consuming. After you publish the apps, you own them – not in the inspirational sense, in the annoying sense. Every app becomes a small surface that needs attention: metadata, screenshots, reviews, ratings, keywords, conversion, cross-promotion, build status, rejections, releases, privacy answers, promo text, support links. Ok, you can catch your breath now. We good? Good, let’s move on. One app is manageable as a pastime, but ten apps are already a small portfolio. And a small portfolio needs systems. So I started building one. The repo is called app-store-release-agent , and, for now, it’s a small Python toolkit for the release workflow itself. Eventually, this could evolve into a full ASO brain. The Business Problem The business problem is simple: maintenance does not scale linearly with motivation. Building an app has a clear dopamine loop. Maintenance is fragmented: a review here, a screenshot there, a keyword set that probably needs work, a support email, a product page that now feels weak. None of these tasks are hard in and by themselves. That is a real and very subtle trap, because they can easily get postponed, and then they pile up. The benefit of an automation pipeline is not only speed. Speed is good, don’t get me wrong, but it’s secondary. The real benefit is lowering the activation energy. If the agent can pull live App Store data, compare it with local metadata, inspect git history, and apply the next release action safely, I do not have to reconstruct the context from scratch every time. A good pipeline should answer three questions quickly: What needs attention now? What can wait? What action has the highest lever

2026-07-11 原文 →
开发者

Game Builder Tutorial 2: Build a Blackjack Card Game (Duke Jack)

In Tutorial 1 Duke dashed for coffee with arcade physics. Now he sets the cup down for a calmer contest: Duke Jack , a game of blackjack. A card game has none of that arcade motion — cards sit on the felt and the rules decide who wins. This tutorial shows how the same Game Builder pattern (visual data + an onUpdate companion) handles a card game, where your code reads the cards and runs the table instead of simulating movement. We'll build a felt table, deal a real hand, and wire up the complete blackjack rules: hit, stand, the dealer's draw, and the win/lose decision. What is Codename One? Codename One is an open-source framework for building native iOS, Android, desktop, and web apps from a single Java or Kotlin codebase. Learn more at codenameone.com . If you haven't set up a project yet, the project setup in Tutorial 1 applies verbatim — only the mode changes (board mode isn't the default, so the -Dmode=board flag is required here): mvn cn1:create-game-scene -DclassName = com.example.dukejack.DukeJack -Dmode = board mvn cn1:gamebuilder Why board mode for cards? Board mode is the Game Builder's grid mode: you place elements on a flat board of cells instead of a free-scrolling world. That's a natural fit for a card table — the felt is a tile layer, and each card is an element you position by hand, carrying its own rank , suit and faceUp data. There's no physics and no camera to chase; the layout is the game state, and your rules read it. (Board mode can also tilt the grid into an isometric view through IsoProjection for tabletop games — for cards we keep it flat and top-down.) Step 1 — A card-table scene Pick New scene → Board . You get a Board (tile) layer for the table surface and a Pieces (entity) layer for the cards. Keeping the felt and the cards on separate layers matters: the felt is static grid data, while the cards are objects your rules deal, flip, and clear. A small grid (here 8×5) is all a card table needs. Step 2 — Lay the felt Select the Board layer,

2026-07-09 原文 →
AI 资讯

Article: Beat-Aligned Mobile Audio Streaming with Virtual Chunks and Native Playback

In this article, I describe the challenges and the design of a React Native real-time mobile beat-aligned playback system for iOS and Android. The system combines personalization with low-latency, and seamless navigation and was the result of careful analysis and experimentation to address strict mobile and network constraints as well as meet user expectations. By Vladyslav Melnychenko

2026-07-09 原文 →
AI 资讯

Stop Rebuilding the Same SwiftUI Components: A Guide to DesignFoundation

"I'll just write a quick button style... and a text field with validation... and a card component..." Two weeks later you have a bespoke design system that only half the app uses, three slightly different buttons, and nothing shipped. If you're building with an AI coding agent, the drift problem is worse, not better. Ask Claude, Cursor, or Codex to "add a settings screen" three separate times and you'll get three different paddings, three different corner radii, and a button style that quietly forked itself somewhere around commit 40. Agents are great at writing plausible SwiftUI and bad at remembering what the rest of your app already decided. DesignFoundation is an open-source SwiftUI package that gives you a token-based theming engine, 25 components, and 6 feedback/overlay modifiers that all read from the same theme. You set it once at the app root, and everything underneath updates. That's the whole idea — and it ships with CLAUDE.md , AGENTS.md , and Cursor rules already written, so an agent working in your repo reaches for DFButton instead of inventing a new one. In this tutorial you'll go from zero to a themed, consistent SwiftUI UI — without writing a single custom button style. What We're Building By the end you'll have: A working app that uses DesignFoundation's theme system A themed form with inputs, validation states, and feedback components A custom theme built from tokens An understanding of how the style system composes Requirements: Xcode 16+, iOS 18+ / macOS 15+ target, Swift 6. Installation Via Xcode File → Add Package Dependencies Paste https://github.com/NerdSnipe-Inc/design-foundation Set the version rule to Up to Next Major from 1.0.0 Add DesignFoundation to your target Via Package.swift dependencies : [ . package ( url : "https://github.com/NerdSnipe-Inc/design-foundation" , from : "1.0.0" ) ], targets : [ . target ( name : "YourApp" , dependencies : [ "DesignFoundation" ]) ] Step 1: One Line Instead of a ThemeManager Singleton Every app that

2026-07-07 原文 →
AI 资讯

Stop Rebuilding Auth, Onboarding, and Dashboards: DesignFoundationPro

Part 2 of 2. This tutorial builds on Part 1 — DesignFoundation core . If you haven't added the base package and theme yet, start there. The core package gives you tokens and primitives. DesignFoundationPro adds what comes next — 29 blocks, 47 screens, 18 navigation shells, and 9 runnable composition examples across auth, onboarding, charts, data tables, and full product verticals. The docs claim ~87% fewer lines of code versus building from scratch. That's the bet. This matters even more if an AI coding agent is doing the building. Ask an agent for a CRM screen and a settings screen in the same session and, without guardrails, you'll get two different takes on spacing, two different sidebar behaviors, and a table that's native on Mac in one screen and a scroll view pretending to be a table in the other. Pro ships with that guardrail already in place — more on that in Where to go from here. How the two packages relate Pro sits on top of Foundation and re-exports it. Import only DesignFoundationPro and you get everything from both: YourApp your models, data, routing DesignFoundationPro 29 blocks · 47 screens · 18 shells · 9 examples DesignFoundation tokens · primitives · validation · theme engine · MIT Access: Foundation is MIT and public. Pro is a commercial add-on — repo access is granted after purchase. Licenses are lifetime (no subscription); annual updates are $39/year and entirely optional. Pricing: $149 individual · $449 team (up to 5 devs). Before buying, browse everything in DFPlayground — a free macOS app that lets you preview all 29 blocks, 47 screens, and 18 shells with live theming. Step 1: Add DesignFoundationPro Pro declares Foundation as its own dependency and re-exports it via @_exported import DesignFoundation . Add only the Pro package — Foundation comes with it automatically. The Pro repo URL is provided after purchase — contact nerdsnipe.inc@gmail.com or visit the Pro page to get access. dependencies : [ . package ( url : "https://github.com/NerdS

2026-07-07 原文 →