Readme da língua chinesa: 中文集成指南
A injeção de código permite atualizar a implementação de funções e qualquer método de classe, estrutura ou enum de forma incremental no simulador iOS sem precisar executar uma reconstrução completa ou reiniciar seu aplicativo. Isso salva ao desenvolvedor uma quantidade significativa de tempo ajustando o código ou iterando um design. Efetivamente, ele muda o Xcode de ser um "editor de origem" para ser um "editor do programa", onde as alterações de fonte não são apenas salvas no disco, mas no seu programa em execução diretamente.
A configuração de seus projetos para usar a injeção agora é tão simples quanto baixar um dos lançamentos do GitHub do aplicativo ou da Mac App Store e adicionar o código abaixo em algum lugar do seu aplicativo para ser executado na inicialização (não é mais necessário executar o próprio aplicativo).
#if DEBUG
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle " ) ? . load ( )
//for tvOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/tvOSInjection.bundle " ) ? . load ( )
//Or for macOS:
Bundle ( path : " /Applications/InjectionIII.app/Contents/Resources/macOSInjection.bundle " ) ? . load ( )
#endif Também é importante adicionar as opções -Xlinker e -interposable (sem cotações duplas e em linhas separadas) aos "outros sinalizadores do vinculador" dos alvos do seu projeto (apenas para a configuração Debug ) para ativar "interposição" (consulte a explicação abaixo).

Depois disso, quando você executa seu aplicativo no simulador, verá uma mensagem dizendo que um observador de arquivos inicia para o seu diretório doméstico e, sempre que você salvar um arquivo de origem no projeto atual, ele deve relatar que foi injetado. Isso significa que todos os lugares que anteriormente chamados de implementação antiga serão atualizados para chamar a versão mais recente do seu código.
Não é tão simples quanto ver os resultados na tela imediatamente, o novo código precisa ter sido chamado. Por exemplo, se você injetar um controlador de visualização, ele precisa forçar um Redisplay. Para resolver esse problema, as classes podem implementar um método @objc func injected() que será chamado depois que a classe foi injetada para executar qualquer atualização para a exibição. Uma técnica que você pode usar é incluir o seguinte código em algum lugar do seu programa:
#if DEBUG
extension UIViewController {
@ objc func injected ( ) {
viewDidLoad ( )
}
}
#endifOutra solução para esse problema é a "hospedagem" usando o pacote Swift Inject introduzido por esta postagem do blog.
Você não pode injetar alterações na forma como os dados são dispostos na memória, ou seja, você não pode adicionar, remover ou reordenar propriedades com armazenamento. Para classes não finais, isso também se aplica aos métodos de adição ou remoção, pois o vtable usado para despacho é uma estrutura de dados que não deve mudar sobre a injeção. A injeção também não pode descobrir quais peças de código precisam ser reexecutadas para atualizar a tela, conforme discutido acima. Além disso, não se empolgue com o controle de acesso. Propriedades e métodos private não podem ser injetados diretamente, principalmente em extensões, pois não são um símbolo interposável global . Eles geralmente injetam indiretamente, pois só podem ser atacidos dentro do arquivo sendo injetado, mas isso pode causar confusão. Finalmente, a injeção não lida bem com os arquivos de origem sendo adicionados/renomeados/excluídos durante a injeção. Pode ser necessário criar e relançar seu aplicativo ou até fechar e reabrir seu projeto para limpar os antigos logs de construção do xcode antigos.
O Swiftui é, se alguma coisa, mais adequado à injeção do que o UIKIT, pois possui mecanismos específicos para atualizar o visor, mas você precisa fazer algumas alterações em cada View que deseja injetar. Para forçar o Redraw, a maneira mais simples é adicionar uma propriedade que observa quando ocorreu uma injeção:
@ ObserveInjection var forceRedraw Este invólucro de propriedade está disponível no pacote HotswiftUi ou Inject Swift. Ele essencialmente contém um número inteiro @Published que suas opiniões observam que incrementos a cada injeção. Você pode usar um dos seguintes seguintes para disponibilizar um desses pacotes ao longo do seu projeto:
@ _exported import HotSwiftUI
or
@ _exported import Inject A segunda alteração que você precisa fazer para uma injeção confiável de Swiftui é "apagar o tipo de retorno" da propriedade do corpo, envolvendo -a em AnyView usando o método .enableInjection() que estende View nesses pacotes. Isso ocorre porque, ao adicionar ou remover os elementos swifttui, ele pode alterar o tipo de retorno concreto da propriedade do corpo, que equivale a uma mudança de layout de memória que pode travar. Em resumo, a extremidade traseira de cada corpo deve sempre ficar assim:
var body : some View {
VStack or whatever {
// Your SwiftUI code...
}
. enableInjection ( )
}
@ ObserveInjection var redraw Você pode deixar essas modificações em seu código de produção, pois, para uma versão Release eles otimizam para um não-operatório.
O novo no Xcode 16 é SWIFT_ENABLE_OPAQUE_TYPE_ERASURE CONFIGURAÇÃO. Essa configuração é ativada por padrão e você não precisa apagar explicitamente o corpo. Você ainda precisará @ObserveInjection para forçar os redefinições.
Para mais informações, consulte o Xcode 16.2 Notas de lançamento.
Isso pode funcionar, mas você precisará executar uma das liberações do GitHub 4.8.0+ do injeçãoiii.app, definir um padrão de usuário para optar e reiniciar o aplicativo.
$ defaults write com.johnholdsworth.InjectionIII deviceUnlock any
Em seguida, em vez de carregar os pacotes de injeção, execute este script em uma "fase de construção": (você também precisará desativar a configuração de construção do projeto "Script de usuário do usuário")
RESOURCES=/Applications/InjectionIII.app/Contents/Resources
if [ -f "$RESOURCES/copy_bundle.sh" ]; then
"$RESOURCES/copy_bundle.sh"
fi
E, em seu aplicativo, execute o seguinte código na inicialização:
#if DEBUG
if let path = Bundle . main . path ( forResource :
" iOSInjection " , ofType : " bundle " ) ??
Bundle . main . path ( forResource :
" macOSInjection " , ofType : " bundle " ) {
Bundle ( path : path ) ! . load ( )
}
#endifDepois de mudar para essa configuração, ela também funcionará ao usar o simulador. Consulte o ReadMe do projeto HotReloading para obter detalhes sobre como depurar, fazendo com que seu programa se conecte ao injeçãoiii.app sobre o Wi-Fi. Você também precisará selecionar o diretório do projeto para o vigilante do arquivo manualmente no menu pop-down.
Funciona, mas você precisa desativar temporariamente a "Sandbox do aplicativo" e a "validação da biblioteca" no "tempo de execução endurecido" durante o desenvolvimento, para que possa carregar dinamicamente o código. Para evitar problemas de design de código, use o script novo copy_bundle.sh conforme detalhado nas instruções de injeção em dispositivos reais acima.
A injeção trabalhou várias maneiras ao longo dos anos, começando usando as APIs "Swizzling" para o Objective-C, mas agora é amplamente construído em torno de um recurso do vinculador da Apple chamado "Interpoação", que fornece uma solução para qualquer método SWIFT ou propriedade calculada de qualquer tipo.
Quando seu código chama uma função no Swift, geralmente é "estaticamente despachado", ou seja, vinculado usando o "símbolo mutilado" da função que está sendo chamada. Sempre que você vincula seu aplicativo à opção "-Interposable", no entanto, um nível adicional de indiretiva é adicionado onde encontra o endereço de todas as funções chamadas através de uma seção de memória gravável. Usando a capacidade do sistema operacional de carregar o código executável e a Biblioteca Fishhook para "rebidar" a chamada, portanto, é possível "interferir" novas implementações de qualquer função e costure -as efetivamente no restante do seu programa em tempo de execução. A partir desse ponto, ele será executado como se o novo código tivesse sido incorporado ao programa.
A injeção usa a API FSEventSteam para observar quando um arquivo de origem foi alterado e verifica o último log de construção do Xcode para como recompensá -lo e vincula uma biblioteca dinâmica que pode ser carregada no seu programa. O suporte ao tempo de execução da injeção carrega a biblioteca dinâmica e a digitaliza para as definições de função que ela contém quais "interpõe" no restante do programa. Esta não é a história completa, pois o despacho de métodos de classe não final usa um "vtable" (pense em métodos virtuais C ++) que também deve ser atualizado, mas o projeto cuida disso, juntamente com qualquer objetivo legado "swizzling".
Se você estiver interessado em saber mais sobre como a injeção funciona, a melhor fonte é o meu livro Swift Secrets ou a nova implementação de referência de partida no pacote Swift injeção. Para obter mais informações sobre "interposição", consulte esta postagem no blog ou o Readme do Projeto Fishhook. Para obter mais informações sobre a organização do próprio aplicativo, consulte o roteiro.md.
Obter injeção para o trabalho tem três componentes. Um FileWatcher, o código para recompilar quaisquer arquivos alterados e criar uma biblioteca dinâmica que possa ser carregada e o próprio código de injeção que costura as novas versões do seu código no aplicativo enquanto estiver em execução. Como esses três componentes são combinados gera o número de maneiras pelas quais a injeção pode ser usada.
"Injeção Classic" é onde você baixa um dos lançamentos binários do Github e executa a injeçãoiii.app. Em seguida, você carrega um dos pacotes dentro desse aplicativo em seu programa, como mostrado acima, no simulador. Nesta configuração, o observador de arquivos e a recompilação de origem são feitos dentro do aplicativo e o pacote se conecta ao aplicativo usando um soquete para saber quando uma nova biblioteca dinâmica está pronta para ser carregada.
"Injeção da App Store" Esta versão do aplicativo está na caixa de areia e, enquanto o observador de arquivos ainda é executado dentro do aplicativo, o recompilação e o carregamento são delegados para serem executados dentro do simulador. Isso pode criar problemas com os arquivos de cabeçalho C, pois o simulador usa um sistema de arquivos sensível ao caso para ser uma simulação fiel de um dispositivo real.
A "injeção de hotreloading" foi onde você está executando seu aplicativo em um dispositivo e, porque não pode carregar um pacote do sistema de arquivos do seu Mac em um telefone real, adiciona o pacote SWIFT com hotreloading ao seu projeto (apenas durante o desenvolvimento!), Que contém todo o código que normalmente estaria no pacote para executar a carga dinâmica. Isso exige que você use um dos lançamentos binários da ONU de caixa de areia. Também foi substituído pelo script copy_bundle.sh descrito acima.
"Injeção independente". Essa foi a evolução mais recente do projeto, onde você não executa mais o aplicativo, mas simplesmente carregue um dos feixes de injeção e o vigilante de arquivos, a recompilação e a injeção são executados dentro do simulador. Por padrão, isso observa as alterações em qualquer arquivo SWIFT dentro do seu diretório inicial, embora você possa alterar isso usando o ambiente Variable INJECTION_DIRECTORIES .
A Injeçãolite é uma implementação mínima de inicialização da injeção independente de referência. Basta adicionar este pacote SWIFT e você poderá injetar no simulador.
A Injeçãonext é uma versão experimental da injeção atualmente que deve ser mais rápida e confiável para grandes projetos. Ele se integra a um sinalizador de depuração do Xcode para descobrir como recompilar arquivos para evitar a análise de logs de criação e reutiliza a implementação do cliente da injeção de InjectionLite . Para usar com editores externos, como Cursor , o InjeçãoNext também pode usar um vigia de arquivos para detectar edições e voltar para criar o código de análise de log.
Todas essas variações exigem que você adicione os sinalizadores "-xlinker -interposble" para uma construção de depuração ou você só poderá injetar métodos de classes não finais e todos podem ser usados em conjunto com qualquer um dos injetados de nível superior ou HotSwiftui.
Consulte o antigo ReadMe que, se alguma coisa continha simplesmente "muita informação", incluindo as várias variáveis de ambiente que você pode usar para personalização. Alguns exemplos:
| Ambiente var. | Propósito |
|---|---|
| Injeção_detail | Saída detalhada de todas as ações executadas |
| Injeção_trace | Chamadas de log para funções injetadas (v4.6.6+) |
| Injeção_host | Endereço IP do MAC para injeção no dispositivo |
Com uma variável de ambiente injeção_trace , a injeção de qualquer arquivo adicionará o registro de todas as chamadas a funções e métodos no arquivo, juntamente com seus valores de argumento como ajuda para depuração.
Um recurso pouco conhecido da injeção é que você tenha executado os testes para o seu aplicativo em algum momento, você pode injetar uma classe XCTest individual e ter se executado imediatamente - relatar se ele falhar cada vez que você o modificar.
Este projeto inclui código de Rentzsch/mach_inject, erwanb/machinjectsample, Davedelong/ddhotkey e ACJ/timelapsebuilder-swift sob suas respectivas licenças.
A funcionalidade de rastreamento de aplicativos usa a implementação de trampolim do OliverLeTterer/IMP_Implementation para a implementação de trampolim do SwiftTrace sob uma licença do MIT.
SwiftTrace usa o muito útil https://github.com/facebook/fishhook. Consulte a fonte do projeto e o arquivo de cabeçalho incluído no pacote de aplicativos para obter detalhes de licenciamento.
Esta versão inclui uma versão muito modificada da excelente biblioteca Canviz para renderizar arquivos "Dot" em uma tela HTML, que está sujeita a uma licença do MIT. As alterações devem passar pelo ID do nó para a etiqueta da etiqueta do nó (linha 212), para reverter a renderização dos nós e as linhas que as ligam (linha 406) e para armazenar caminhos de borda para que possam ser coloridos (linha 66 e 303) em "canviz-0.1/canviz.js".
Ele também inclui o Codemirror JavaScript Editor para que o código seja avaliado usando injeção sob uma licença do MIT.
O Fabulous App Icon é graças a Katya do Pixel-Mixer.com.