Desenvolvimento de aplicativos do ADOBE AIR 1.5 com o ADOBE FLASH CS4 PROFESSIONAL ® ® ™ ® © 2008 Adobe Systems Incorporated. Todos os direitos reservados. Copyright Desenvolvimento de aplicativos Adobe® AIR™ 1.5 com o Adobe® Flash® CS4 Se distribuído com o software que inclui um acordo de usuário final, este guia, juntamente com o software nele descrito, ficará sujeito à licença, podendo ser usado ou copiado apenas de acordo com os termos dessa licença. Exceto conforme permitido por esta licença, nenhuma parte deste guia pode ser reproduzida, armazenada em um sistema de recuperação ou transmitida, em nenhuma forma ou meio eletrônico, mecânico, de gravação, ou semelhante, sem a permissão prévia por escrito da Adobe Systems Incorporated. Observe que o conteúdo deste guia está protegido por leis de direitos autorais, mesmo não sendo distribuído com o software que inclui um contrato de licença de usuário final. O conteúdo deste guia foi desenvolvido apenas para fins informativos, está sujeito a alterações sem aviso prévio e não deve ser considerado um compromisso firmado pela Adobe Systems Incorporated. A Adobe Systems Incorporated não se responsabiliza por erros ou imprecisões que possam aparecer no conteúdo informativo deste guia. Lembre-se de que os desenhos ou imagens existentes e cogitados para inclusão em projetos podem estar protegidos por leis de direitos autorais.. A incorporação não autorizada desse material em um novo trabalho pode ser considerada uma violação dos direitos autorais do respectivo detentor. Certifique-se de obter a permissão necessária do detentor em questão. Todas as referências a nomes de empresas ou pessoas em modelos de amostra são apenas para fins demonstrativos e não têm o objetivo de fazer alusões a nenhuma pessoa ou organização real. Adobe, the Adobe logo, Acrobat, ActionScript, Adobe AIR, ColdFusion, Dreamweaver, Flash, Flex, Flex Builder, and Reader are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries. Microsoft and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. Apple, Macintosh, and Mac OS are trademarks of Apple Inc., registered in the United States and other countries. Java is a trademarks or registered trademark of Sun Microsystems, Inc. in the United States and other countries. Linux is the registered trademark of Linus Torvalds in the U.S. and other countries. All other trademarks are the property of their respective owners. This work is licensed under the Creative Commons Attribution Non-Commercial 3.0 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/us/ This product includes software developed by the Apache Software Foundation (http://www.apache.org/) MPEG Layer-3 audio compression technology licensed by Fraunhofer IIS and Thomson Multimedia (http://www.mp3licensing.com). Speech compression and decompression technology licensed from Nellymoser, Inc. (www.nellymoser.com) Video compression and decompression is powered by On2 TrueMotion video technology. © 1992-2005 On2 Technologies, Inc. All Rights Reserved. http://www.on2.com. This product includes software developed by the OpenSymphony Group (http://www.opensymphony.com/) This product contains either BSAFE and/or TIPEM software by RSA Security, Inc. Sorenson Spark™ video compression and decompression technology licensed from Sorenson Media, Inc. This product includes software developed by the IronSmith Project (http://www.ironsmith.org/). Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA. Notice to U.S. Government End Users. The Software and Documentation are “Commercial Items,” as that term is defined at 48 C.F.R. §2.101, consisting of “Commercial Computer Software” and “Commercial Computer Software Documentation,” as such terms are used in 48 C.F.R. §12.212 or 48 C.F.R. §227.7202, as applicable. Consistent with 48 C.F.R. §12.212 or 48 C.F.R. §§227.7202-1 through 227.7202-4, as applicable, the Commercial Computer Software and Commercial Computer Software Documentation are being licensed to U.S. Government end users (a) only as Commercial Items and (b) with only those rights as are granted to all other end users pursuant to the terms and conditions herein. Unpublished-rights reserved under the copyright laws of the United States. Adobe Systems Incorporated, 345 Park Avenue, San Jose, CA 95110-2704, USA. For U.S. Government End Users, Adobe agrees to comply with all applicable equal opportunity laws including, if appropriate, the provisions of Executive Order 11246, as amended, Section 402 of the Vietnam Era Veterans Readjustment Assistance Act of 1974 (38 USC 4212), and Section 503 of the Rehabilitation Act of 1973, as amended, and the regulations at 41 CFR Parts 60-1 through 60-60, 60-250, and 60-741. The affirmative action clause and regulations contained in the preceding sentence shall be incorporated by reference. iii Conteúdo Capítulo 1: Instalação do Adobe AIR Instalação do Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Remoção do Adobe AIR ............................................................................................... 2 Instalação e execução de aplicativos de amostra do AIR ................................................................ 2 Capítulo 2: Configuração do Flash CS3 para Adobe AIR Requisitos de sistema para atualização do Adobe AIR para Flash CS3 .................................................... 3 Instalação da atualização do Adobe AIR para Flash CS3 ................................................................. 3 Remoção da atualização do Adobe AIR para Flash CS3 .................................................................. 4 Adições do AIR para o Flash CS3 ....................................................................................... 5 Capítulo 3: Introdução ao Adobe AIR Novidades do AIR 1.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Novidades do AIR 1.5 .................................................................................................. 8 Capítulo 4: Localização de recursos do AIR Capítulo 5: Criação do seu primeiro aplicativo AIR usando o Flash CS3 ou CS4 Criar aplicativo Hello World no Flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Testar o aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Converter um arquivo FLA em um aplicativo Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Capítulo 6: Atualização do Adobe AIR para Flash CS3 Professional Criar um arquivo Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Definição das configurações de publicação do Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Visualizar um aplicativo Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Depurar um aplicativo Adobe AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Criação de arquivos do aplicativo AIR e do instalador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Criação de um arquivo personalizado de descrição do aplicativo Assinatura do aplicativo Capítulo 7: Segurança do AIR Noções básicas de segurança do AIR Instalação e atualizações Caixas de proteção segurança HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Script entre conteúdos em domínios distintos Gravação em disco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Trabalho seguro com conteúdo não confiável . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Práticas recomendadas de segurança para desenvolvedores Assinatura de código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Capítulo 8: Configuração de propriedades do aplicativo do AIR A estrutura do arquivo do descritor do aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Definição de propriedades no arquivo do descritor do aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL iv Conteúdo Capítulo 9: Adobe AIR - funcionalidade específica Classes específicas do AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Classes de tempo de execução com funcionalidade específica do AIR Classes de estrutura de monitoramento de serviço Capítulo 10: Trabalhar com janelas nativas Mais informações on-line sobre janelas nativas Noções básicas sobre janelas do AIR Criação de janelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Gerenciamento de janelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Monitorando eventos de janela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Exibição de janelas em tela cheia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Capítulo 11: Telas Informações on-line adicionais sobre telas Noções básicas de tela Enumeração de telas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Capítulo 12: Trabalho com menus nativos Informações online adicionais sobre menus nativos Noções básicas do menu AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Criação de menus nativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Sobre menus de contexto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Sobre menus de contexto em HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Definição de forma clara de menus nativos Exibição de menus pop-up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Tratamento de itens de menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Exemplo: Menu de janela e aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Capítulo 13: Ícones na barra de tarefas Informações on-line adicionais sobre ícones da barra de tarefas Sobre ícones na barra de tarefas Ícones de encaixe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 Ícones da bandeja do sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 Ícones e botões da barra de tarefas do Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 Capítulo 14: Trabalho com o sistema de arquivos Informações adicionais on-line sobre a API de Arquivo AIR Noções básicas do arquivo AIR Trabalho com objetos File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Obtenção de informações sobre o sistema de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 Trabalho com diretórios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Trabalho com arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Leitura e gravação de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Capítulo 15: Arrastar e soltar Informações online adicionais sobre arrastar e soltar Conceitos básicos de arrastar e soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL v Conteúdo Suporte ao gesto de arrastar para fora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 Suporte ao gesto de arrastar para dentro HTML arrastar e soltar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Capítulo 16: Copiar e colar Informações online adicionais sobre copiar e colar Copiar e colar HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Comandos de menu e pressionamentos de tecla para copiar e colar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Capítulo 17: Trabalhar com matrizes de bytes Ler e escrever um ByteArray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Exemplo de ByteArray: leitura de um arquivo .zip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 Capítulo 18: Trabalhar com bancos de dados SQL locais Mais informações on-line sobre bancos de dados SQL locais Sobre bancos de dados SQL locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Criação e modificação de um banco de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Manipulação de dados de um banco de dados SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Uso de operações de banco de dados síncronas e assíncronas Uso da criptografia com bancos de dados SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Estratégias para trabalhar com bancos de dados SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 Capítulo 19: Armazenamento de dados criptografados Capítulo 20: Sobre o ambiente HTML Visão geral do ambiente HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Extensões do AIR e Webkit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 Capítulo 21: Programação em HTML e JavaScript Sobre a classe HTMLLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 Como evitar erros JavaScript relacionados à segurança Acesso às classes API do AIR no JavaScript Sobre URLs no AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240 Como tornar objetos ActionScript disponíveis para JavaScript Acesso a objetos HTML DOM e JavaScript do ActionScript Incorporação de conteúdo SWF em HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 Uso de bibliotecas do ActionScript em uma página HTML Conversão de objetos Date e RegExp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 Manipulação de folha de estilos HTML do ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 Conteúdo entre scripts em caixas de proteção de segurança distintas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248 Capítulo 22: Tratamento de eventos relacionados a HTML eventos HTMLLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 Tratamento de eventos DOM com o ActionScript Resposta a exceções JavaScript não capturadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Tratamento de eventos de tempo de execução com JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL vi Conteúdo Capítulo 23: Gravação de script de contêiner HTML Exibição de propriedades de objetos HTMLLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258 Rolagem de conteúdo HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 Acesso à lista de histórico de HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 Definição do agente do usuário usado ao carregar conteúdo HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 Configuração de codificação de caractere para uso de conteúdo HTML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 Definição de interfaces do usuário como navegadores para conteúdo HTML Criação de subclasses da classe HTMLLoader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270 Capítulo 24: Adição de conteúdo em PDF Detecção de recurso de PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 Carregamento de conteúdo em PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 Gravando em script o conteúdo em PDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 Limitações conhecidas do conteúdo em PDF no AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 Capítulo 25: Utilização de gerenciamento de direitos digitais Informações online adicionais sobre o gerenciamento de direitos digitais Compreensão do fluxo de trabalho FLV criptografado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 Membros e eventos relacionados a DRM da classe NetStream Uso da classe DRMStatusEvent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 Uso da classe DRMAuthenticateEvent Uso da classe DRMErrorEvent Uso da classe DRMManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288 Uso da classe DRMContentData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290 Capítulo 26: Inicialização do aplicativo e opções de saída Invocação do aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 Captura de argumentos de linha de comando Inicialização no login . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Invocação do navegador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294 Encerramento do aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296 Capítulo 27: Leitura de configurações do aplicativo Leitura do arquivo do descritor do aplicativo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 Como obter os identificadores de aplicativo e editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298 Capítulo 28: Trabalho com tempo de execução e informações do sistema operacional Gerenciamento de associações de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 Obtenção da versão do tempo de execução e do nível de patch Detecção de recursos do AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 Rastreamento de presença do usuário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300 Capítulo 29: Monitoramento de conectividade de rede Detecção de alterações na conectividade de rede . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 Noções básicas de monitoramento de serviço Detecção de conectividade HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 Detecção de conectividade de soquete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL vii Conteúdo Capítulo 30: Solicitações de URL e rede Uso da classe URLRequest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 305 Alterações feitas na classe URLStream . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 Abertura de uma URL no navegador da Web padrão do sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308 Capítulo 31: Comunicação entre aplicativos Capítulo 32: Distribuição, instalação e execução de aplicativos do AIR Instalação e execução de um aplicativo do AIR da área de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312 Instalação e execução de aplicativos do AIR de uma página da Web Implantação empresarial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 Assinatura digital de um arquivo do AIR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321 Capítulo 33: Atualização de aplicativos do AIR Sobre atualização de aplicativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 Apresentação de uma interface de usuário de atualização do aplicativo personalizado Download de um arquivo do AIR no computador do usuário Verificar se um aplicativo está sendo executado pela primeira vez Uso da estrutura de atualização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 Capítulo 34: Localização de aplicativos AIR Introdução à localização . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 Localização do nome e da descrição do aplicativo no instalador do aplicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 Seleção de código de idiomas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 Localização de conteúdo Flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 Localização de conteúdo HTML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 Localização de datas, horas e moedas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 Capítulo 35: Criação de um aplicativo do AIR usando as ferramentas de linha de comando Uso do ADL (AIR Debug Launcher) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Empacotamento de um arquivo de instalação do AIR usando o ADT (ferramenta para desenvolvedores do AIR) Assinatura de um arquivo do AIR para alterar o certificado do aplicativo Criação de um certificado auto-assinado com o ADT Uso do Apache Ant com as ferramentas do SDK Índice . . . . . . . . 357 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 1 Capítulo 1: Instalação do Adobe AIR O Adobe® AIR™ permite executar aplicativos AIR na área de trabalho. É possível instalar o tempo de execução das seguintes formas: • Instalando o tempo de execução separadamente (sem instalar também um aplicativo AIR) • Instalando o aplicativo AIR pela primeira vez (você é solicitado a também instalar o tempo de execução) • Configurando um ambiente de desenvolvimento AIR como o AIR SDK, Adobe® Flex™ Builder™ 3, ou Adobe Flex™ 3 SDK(que inclui as ferramentas de desenvolvimento de linha de comando do AIR) Só é necessário instalar o tempo de execução uma vez por computador. Os requisitos do sistema para instalar o AIR e executar aplicativos do AIR são detalhados aqui: Adobe AIR: Requisitos do sistema (http://www.adobe.com/products/air/systemreqs/). Instalação do Adobe AIR Use as seguintes instruções para fazer download e instalar as versões do AIR para Windows®, Mac OS X e Linux. Para atualizar o tempo de execução, o usuário deve ter privilégios administrativos no computador. Instalação do tempo de execução em um computador com Windows 1 Faça download do arquivo de instalação do tempo de execução. 2 Clique duas vezes no arquivo de instalação do tempo de execução. 3 Na janela de instalação, siga os avisos para concluir a instalação. Instalação do tempo de execução em um computador com Mac 1 Faça download do arquivo de instalação do tempo de execução. 2 Clique duas vezes no arquivo de instalação do tempo de execução. 3 Na janela de instalação, siga os avisos para concluir a instalação. 4 Se o instalador exibir a janela Autenticação, insira seu nome de usuário e sua senha do Mac OS. Instalação do tempo de execução em um computador com Linux 1 Baixe o arquivo de instalação do tempo de execução. 2 Defina as permissões de arquivo para que seja possível executar o aplicativo instalador. De uma linha de comando, você pode definir as permissões de arquivo com o comando chmod +x installer.bin. Algumas versões do Linux permitem definir as permissões de arquivo na caixa de diálogo Propriedades aberta por meio de um menu de contexto. 3 Execute o instalador da linha de comando ou clicando duas vezes no arquivo de instalação do tempo de execução. 4 Na janela de instalação, siga os avisos para concluir a instalação. O AIR é instalado como pacotes rpm ou dpkg, com nomes de pacote: adobeairv.n e adobecerts. A instalação requer um servidor X em execução. O AIR registra o tipo mime: application/vnd.adobe.air-application-installerpackage+zip. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 2 Instalação do Adobe AIR Remoção do Adobe AIR Após instalar o tempo de execução, você poderá removê-lo usando os seguintes procedimentos. Remoção do tempo de execução em um computador com Windows 1 No menu Iniciar do Windows, selecione Configurações > Painel de controle. 2 Selecione o painel de controle Adicionar ou remover programas 3 Selecione “Adobe AIR” para remover o tempo de execução. 4 Clique no botão Alterar/remover. Remoção do tempo de execução em um computador com Mac • Clique duas vezes em “Desinstalador do Adobe AIR”, localizado na pasta /Aplicativos/Utilitários. Remoção do tempo de execução em um computador com Linux Execute um dos seguintes procedimentos: • Selecione o comando “Adobe AIR Uninstaller” no menu Aplicativos. • Execute o binário instalador do AIR com a opção -uninstall. • Remova os pacotes do AIR (adobeairv.n e adobecerts) com o gerenciador de pacotes. Instalação e execução de aplicativos de amostra do AIR Alguns aplicativos de amostra estão disponíveis para demonstrar recursos do AIR Você pode acessá-los e desinstalálos usando as seguintes instruções: 1 Faça download e execute os aplicativos de amostra do AIR. Os aplicativos compilados, bem como o código fonte, estão disponíveis. 2 Para fazer download e executar o aplicativo de amostra, clique no botão Instalar agora do aplicativo de amostra. Você é solicitado a instalar e executar o aplicativo. 3 Se você optar por fazer download de aplicativos de amostra e executá-los mais tarde, selecione os links de download. Você pode executar aplicativos AIR a qualquer momento: • No Windows, clicando duas vezes no ícone do aplicativo na área de trabalho, ou selecionando-o no menu Iniciar do Windows. • No Mac OS, clicando duas vezes no ícone do aplicativo, que está instalado na pasta Aplicativos do diretório do usuário (por exemplo, no Macintosh, HD/Users/JoeUser/Applications/), por padrão. • No Linux, clicando duas vezes no ícone do aplicativo na área de trabalho, ou selecionando-o no menu Aplicativos. Os aplicativos do AIR são instalados em sua própria pasta no diretório /opt. Nota: Verifique as notas de versão do AIR para atualizações dessas instruções, que estão localizadas aqui: http://www.adobe.com/go/learn_air_relnotes_br. 3 Capítulo 2: Configuração do Flash CS3 para Adobe AIR A atualização do Adobe® AIR™ para o Adobe® Flash® CS3 Professional aumenta o ambiente de desenvolvimento do Flash com elementos que permitem criar aplicativos do AIR com o Flash. Isso permite criar, testar e depurar arquivos de aplicativos do AIR no Flash. O Adobe® Flash® CS4 Professional tem suporte incorporado para criação de aplicativos AIR. Para obter mais informações, consulte Publicação para o Adobe AIR em Como usar o Flash. A Atualização do Adobe AIR para Flash CS3 dá suporte ao AIR 1.0 e 1.1 e ao Flash Player 9.x. O Flash CS4 é necessário para desenvolver aplicativos com o AIR 1.5 e o Flash Player 10. Requisitos de sistema para atualização do Adobe AIR para Flash CS3 Para usar o Flash CS3 para desenvolver e executar aplicativos do AIR, você deve ter o seguinte software instalado: • Flash CS3 Professional Se você não tiver uma cópia do Flash CS3 Professional, poderá adquiri-la no site da Adobe: http://www.adobe.com/products/flash/ • Adobe AIR Para obter informações sobre a instalação do Adobe AIR, consulte “Instalação do Adobe AIR” na página 1. • Atualização do Adobe AIR para o Flash CS3 Se você tiver instalado anteriormente uma versão da atualização do Adobe AIR para Flash CS3, primeiro remova-a seguindo as etapas em Desinstalação da atualização do Adobe AIR para Flash CS3. Se você não tiver instalado anteriormente a atualização do Adobe AIR para Flash CS3, continue na seção “Instalação da atualização do Adobe AIR para Flash CS3” na página 3. Instalação da atualização do Adobe AIR para Flash CS3 Antes de instalar a atualização do Adobe AIR para Flash CS3, saia do Flash e também de qualquer navegador que estiver aberto. • Faça download da atualização do Adobe AIR para Flash CS3. • Depois de fazer download da atualização, clique duas vezes no arquivo patch de atualização para instalá-la. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 4 Configuração do Flash CS3 para Adobe AIR Remoção da atualização do Adobe AIR para Flash CS3 Se você tiver instalado anteriormente a atualização do Adobe AIR para Flash CS3, siga estas etapas para removê-la antes de instalar uma nova atualização do Adobe AIR para Flash CS3. 1 Excluir a seguinte pasta: (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\AIK (Mac) HD:/Aplicativos/Adobe Flash CS3/AIK 2 Vá para o local a seguir: (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\<lang>\First Run\Commands\ (Mac) HD:/Aplicativos/Adobe Flash CS3/First Run/Commands e exclua os seguintes arquivos/pastas: • pasta AIR • AIR - Application and Installer Settings.jsfl • AIR - Create AIR File.jsfl 3 Exclua o seguinte arquivo: (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\<lang>\Configuration\External Libraries\FLAir.dll (Mac) HD:/Aplicativos/Adobe Flash CS3/Configuration/External Libraries/FLAir.bundle. 4 Exclua o seguinte arquivo: (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\<lang>\Configuration\Players\AdobeAIR1_0.xml (Mac) HD:/Aplicativos/Adobe Flash CS3/Configuration/Players/ AdobeAIR1_0.xml 5 Vá para o local a seguir: (Windows) HD:\Document and Settings\<username>\Configurações locais\Application Data\Adobe\Flash CS3\<lang>\Configuration\Commands\ (Mac) HD:/Users/<username>/Library/Application Support/Adobe/Flash CS3/<lang>/Configuration/Commands/ e exclua os seguintes arquivos/pastas: • pasta AIR • AIR - Application and Installer Settings.jsfl • AIR - Create AIR File.jsfl Nota: Se você não vir o local especificado no Windows, ative a opção "Mostrar pastas e arquivos ocultos" nas opções de pasta. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 5 Configuração do Flash CS3 para Adobe AIR Adições do AIR para o Flash CS3 Depois de instalar a atualização do Adobe AIR, você poderá ver as seguintes alterações no Flash: • Na caixa de diálogo Configurações de publicação (Arquivo > Configurações de publicação), na aba Flash, uma nova entrada no menu Versão para Adobe AIR 1.0. • Uma tela atualizada de boas-vindas que contém uma entrada para a criação de arquivo Flash (Adobe AIR). (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\FirstRun\StartPage (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\FirstRun\StartPage\resources Observação: em um computador MacIntosh, se Arquivo Flash (Adobe AIR) não for exibido na tela de boas-vindas, exclua a pasta a seguir e reinicie o Flash: HD:/Users/<username>/Libraries/Application Support/Adobe/Flash CS3/<language>/Configuration/StartPage • Um novo arquivo playerglobal.swc que inclui todas as APIs do ActionScript 3.0 e do Adobe AIR na pasta ActionScript 3.0/Classes (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\Configuration\ActionScript 3.0 Classes (Mac) HD:/Aplicativos/Adobe Flash CS3/Configuration/ActionScript 3.0/Classes/ • Novos arquivos jsfl (AIR - Application and Installer Settings.jsfl, AIR - Publish AIR File.jsfl) (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\FirstRun\Commands (Mac) HD:/Aplicativos/Adobe Flash CS3/First Run/Commands/ • Adobe AIR Software Development Kit (AIK) (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\AIK • Biblioteca externa (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\Configuration\External Libraries (Mac) HD:/Aplicativos/Adobe Flash CS3/Configuration/External Libraries/ • Arquivo de configurações de destino (Windows) HD:\Arquivos de programas\Adobe\Adobe Flash CS3\en\Configuration\Players\ (Mac) HD:/Aplicativos/Adobe Flash CS3/Configuration/Players 6 Capítulo 3: Introdução ao Adobe AIR O Adobe® AIR™ é um tempo de execução entre vários sistemas operacionais que permite potencializar suas habilidades existentes de desenvolvimento para Web (Adobe® Flash® CS3 Professional, Adobe® Flash® CS4 Professional, Adobe® Flex™, Adobe® ActionScript® 3.0, HTML, JavaScript®, Ajax) para criar e implantar RIAS (Aplicações ricas para internet) na área de trabalho. Você pode encontrar mais informações sobre introdução e uso do Adobe AIR na Conexão de desenvolvedores do Adobe AIR em (http://www.adobe.com/devnet/air/). O AIR permite trabalhar em ambientes familiares, potencializar as ferramentas e abordagens que você considera mais confortáveis e, oferecendo suporte a Flash, Flex, HTML, JavaScript e Ajax, criar a melhor experiência possível que atenda a suas necessidades. Por exemplo, os aplicativos podem ser desenvolvidos usando uma das seguintes tecnologias ou uma combinação delas: • Flash / Flex / ActionScript • HTML / JavaScript / CSS / Ajax • O PDF pode ser potencializado com qualquer aplicativo Como resultado, os aplicativos AIR podem ser: • Baseados em Flash ou Flex: Aplicativos cujo conteúdo de raiz é Flash/Flex (SWF) • Baseados em Flash ou Flex com HTML ou PDF. Aplicativos cujo conteúdo de raiz seja Flash/Flex (SWF) com conteúdo HTML (HTML, JS, CSS) ou PDF incluído • Baseado em HTML. Aplicativo cujo conteúdo de raiz seja HTML, JS e CSS • Baseado em HTML com Flash/Flex ou PDF. Aplicativos cujo conteúdo de raiz seja HTML com conteúdo Flash/Flex (SWF) ou PDF incluído Usuários interagem com aplicativos AIR da mesma forma que interagem com aplicativos nativos da área de trabalho. O tempo de execução é instalado uma vez no computador do usuário e, em seguida, os aplicativos AIR são instalados e executados exatamente como qualquer outro aplicativo da área de trabalho. O tempo de execução oferece uma plataforma cruzada de sistema operacional e estrutura para implantação de aplicativos e, portanto, elimina os testes entre navegadores, assegurando funcionalidade e interações consistentes entre áreas de trabalho. Em vez de desenvolver para um sistema operacional específico, você direciona o tempo de execução, o que oferece seguintes benefícios: • Aplicativos desenvolvidos para execução do AIR através de vários sistemas operacionais sem nenhum trabalho adicional feito por você. O tempo de execução assegura apresentações e interações previsíveis e consistentes entre todos os sistemas operacionais com suporte do AIR. • Os aplicativos podem ser criados mais rapidamente, permitindo potencializar as tecnologias da Web existentes e o padrão de projetos, além de estender seus aplicativos baseados na Web para a área de trabalho sem ter que aprender as tecnologias tradicionais de desenvolvimento da área de trabalho ou a complexidade do código nativo. • O desenvolvimento de aplicativo é mais fácil do que usar linguagens de níveis inferiores, como C e C++. Você não precisa gerenciar APIs complexas de nível inferior, específicas de cada sistema operacional. Ao desenvolver aplicativos para o AIR, você pode potencializar um enorme conjunto de estruturas e APIs: • APIs específicas do AIR fornecidas pelo tempo de execução e pela estrutura AIR DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 7 Introdução ao Adobe AIR • APIs do ActionScript usadas em arquivos SWF e na estrutura Flex (bem como outras bibliotecas e estruturas baseadas no ActionScript) • HTML, CSS e JavaScript • Maioria das estruturas Ajax O AIR altera significativamente o modo como os aplicativos podem ser criados, implantados e experimentados. Você obtém mais controle criativo e pode estender os aplicativos baseados em Flash, Flex, HTML e Ajax para a área de trabalho, sem ter que aprender as tecnologias tradicionais de desenvolvimento para área de trabalho. Novidades do AIR 1.1 O Adobe AIR 1.1 apresentou os novos recursos a seguir: • Instalação e outras caixas de diálogo de tempo de execução foram traduzidos para os idiomas: • Português (Brasil) • Chinês (Tradicional e simplificado) • Francês • Alemão • Italiano • Japonês • Coreano • Russo • Francês • Espanhol • Suporte para criação de aplicativos internacionalizados, incluindo entrada de teclado para idiomas de bytes duplos. Consulte “Localização de aplicativos AIR” na página 343. • Suporte para localização de nome e atributos de descrição no arquivo de descrição do aplicativo. • Suporte para localização de mensagens de erro, como SQLError.detailID e SQLError.detailArguments, no banco de dados SQLite. • Adição da propriedade Capabilities.languages para obter uma matriz de idiomas preferidos de interface do usuário, como definidos pelo sistema operacional. • Rótulos de botão e menus padrão HTML, como menus de contexto e a barra de menu Mac, foram localizados em todos os idiomas suportados. • Suporte para migração de certificado de um aplicativo auto-assinado para um que se vincule a uma CA (Autoridade de certificação). • Suporte para Microsoft Windows XP Tablet PC Edition e suporte para edições de 64 bits do Windows Vista® Home Premium, Business, Ultimate ou Enterprise. • Adição da API File.spaceAvailable, para obter a quantidade de espaço disponível em um disco. • Adição da propriedade NativeWindow.supportsTransparency para determinar se uma janela pode ser desenhada como transparente pelo sistema operacional atual. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 8 Introdução ao Adobe AIR Para obter mais informações sobre a versão AIR 1.1, consulte as Notas de versão do Adobe AIR 1.1 (http://www.adobe.com/go/learn_air_relnotes_en). Novidades do AIR 1.5 O Adobe AIR 1.5 apresentou os novos recursos a seguir: • Suporte para os seguintes recursos do Flash Player 10. • Filtros e efeitos personalizados • API de desenho aprimorada • Geração dinâmica de sons • Tipo de dados vetoriais • APIs aprimoradas para carregar e baixar arquivos • Protocolo RTMFP (Real Time Media Flow Protocol) • Efeitos 3D • Suporte avançado de texto • Gerenciamento de cores • Mecanismo de texto • Fluxo dinâmico • Codec de áudio Speex Para obter mais informações, consultehttp://www.adobe.com/products/flashplayer/features/ para obter detalhes sobre esses recursos. • Idiomas adicionais com suporte no instalador do AIR 1.5 e em outras caixas de diálogo de tempo de execução: tcheco, holandês, sueco, turco e polonês. • Criptografia de banco de dados. Arquivos de banco de dados podem ser criptografados no AIR 1.5. Todo o conteúdo do banco de dados, incluindo os metadados, podem ser criptografados para que os dados não possam ser lidos fora do aplicativo do AIR que os criptografou. Esse recurso permitirá ao desenvolvedor criptografar, descriptografar e criptografar novamente os arquivos do banco de dados. Consulte “Armazenamento de dados criptografados” na página 215. • A versão de WebKit usada pelo Adobe AIR foi atualizada e agora inclui suporte para o intérprete SquirrelFish do JavaScript. • Novas APIs de validação de assinatura XML que podem ser usadas para verificar a integridade e a identidade de quem assina dados ou informações. Consulte Validação da assinatura XML. Para obter mais informações sobre a versão AIR 1,5, consulte as Notas de versão do Adobe AIR 1.5 (http://www.adobe.com/go/learn_air_relnotes_en). 9 Capítulo 4: Localização de recursos do AIR Para obter mais informações sobre o desenvolvimento de aplicativos Adobe® AIR™, consulte os seguintes recursos: Origem Localização Programação do ActionScript 3.0 http://www.adobe.com/go/learn_fl_cs4_programmingAS3_en Referência dos componentes e da linguagem do ActionScript 3.0 (inclui o AIR) http://www.adobe.com/go/learn_flashcs4_langref_en Início rápido do Adobe AIR para Flash http://www.adobe.com/go/learn_air_flash_qs_en Uso do Flash http://www.adobe.com/go/learn_fl_cs4_using_en Uso de componentes do ActionScript 3.0 http://www.adobe.com/go/learn_fl_cs4_as3components_en Você pode encontrar artigos, amostras e apresentações da Adobe e de especialistas da comunidade na Conexão de desenvolvedores do Adobe AIR em http://www.adobe.com/devnet/air/. Você também pode baixar o Adobe AIR e software relacionado nesse endereço. Você pode encontrar uma seção específica para desenvolvedores Flash em http://www.adobe.com/devnet/air/flash/. Visite o site de suporte da Adobe, em http://www.adobe.com/support/, para encontrar informações para solução de problemas do seu produto e saber sobre as opções de suporte técnico paga e gratuita. Siga o link Treinamento para acessar os livros da Adobe Press, uma variedade de recursos de treinamento, programas de certificação de software da Adobe e mais. 10 Capítulo 5: Criação do seu primeiro aplicativo AIR usando o Flash CS3 ou CS4 Para ver uma demonstração rápida e prática de como funciona o Adobe® AIR™, siga as instruções deste tópico para criar e compactar um aplicativo AIR “Hello World” simples utilizando o Adobe® Flash® CS3 Professional. Faça download e instale as atualizações do Adobe AIR para Flash CS3, se ainda não tiver feito isso. Para obter mais informações sobre a instalação do Adobe AIR para Flash CS3, consulte “Configuração do Flash CS3 para Adobe AIR” na página 3. Se você estiver usando o Adobe ®Flash® CS4 Professional, o suporte para o Adobe AIR está incorporado; não é necessário instalar nada para começar. Criar aplicativo Hello World no Flash A criação de um aplicativo Adobe AIR no Flash é semelhante à criação de qualquer outro arquivo FLA. A diferença é que você começará criando um Arquivo Flash (Adobe AIR) na tela de boas-vindas e terminará criando as configurações do aplicativo e do instalador e instalando seu aplicativo AIR. O procedimento a seguir orienta no processo de criação de um aplicativo Hello World simples utilizando o Flash CS3 ou o Flash CS4. Para criar o aplicativo Hello World 1 Inicie o Flash. 2 Na tela de boas-vindas, clique em Arquivo Flash (Adobe AIR) para criar um arquivo FLA vazio com as configurações de publicação do Adobe AIR. 3 Clique em OK para responder o diálogo de resumo, Autoria para Adobe AIR com Flash CS3. Esse diálogo demora alguns segundos para ser exibido pela primeira vez. (Esse diálogo não é exibido no Flash CS4.) 4 Selecione a ferramenta Texto no painel Ferramentas e crie um campo de texto estático (o padrão) no centro do Palco. Faça-o grande o suficiente para conter de 15 a 20 caracteres. 5 Digite o texto "Hello World" no campo de texto. 6 Salve o arquivo, nomeando-o (por exemplo, helloAIR). Testar o aplicativo 1 Pressione Ctrl + Enter ou selecione Controlar -> Testar filme para testar o aplicativo no Adobe AIR. 2 Para utilizar o recurso Depurar filme, primeiro adicione o código ActionScript ao aplicativo. Você pode fazer isso rapidamente adicionando uma instrução trace como esta: trace("Running AIR application using Debug Movie"); 3 Pressione Ctrl + Shift + Enter ou selecione Controlar -> Depurar filme para executar o aplicativo com Depurar filme. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 11 Criação do seu primeiro aplicativo AIR usando o Flash CS3 ou CS4 4 Selecione Comandos > AIR > Configurações do aplicativo e do instalador para abrir a caixa de diálogo AIR - Configurações do aplicativo e do instalador. No Flash CS4, você pode abrir essa caixa de diálogo selecionando Arquivo > AIR - Configurações. 5 Assine o pacote do Adobe AIR com um certificado digital auto-assinado: a Clique no botão Definir... no prompt Assinatura digital para abrir a caixa de diálogo Assinatura digital. b Clique no botão Criar... para abrir a caixa de diálogo Criar certificado digital auto-assinado. c Preencha as entradas para Nome do editor, Unidade organizacional, Nome da organização, E-mail, País, Senha e Confirmar senha. d Especifique o tipo de certificado. A opção Tipo de certificado refere-se ao nível de segurança: 1024-RSA usa uma chave de 1024 bits (menos segura) e 2048-RSA usa uma chave de 2048 bits (mais segura). e Salve as informações em um arquivo de certificado preenchendo a entrada Salvar como ou clicando no botão Procurar... para procurar o local da pasta. (Por exemplo, C:/Temp/mycert.pfx). Quando terminar, clique em OK. f O Flash retorna para o diálogo Assinatura digital. O caminho e o nome de arquivo do certificado auto-assinado que você criou são exibidos na caixa de texto Certificado. Se isso não ocorrer, digite o caminho e o nome de arquivo ou clique no botão Procurar para localizá-lo e selecioná-lo. g Digite a mesma senha no campo de texto Senha da caixa de diálogo Assinatura digital que você atribuiu na Etapa C e clique em OK. Para obter mais informações sobre assinatura de aplicativos Adobe AIR, consulte “Assinatura do aplicativo” na página 21. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 12 Criação do seu primeiro aplicativo AIR usando o Flash CS3 ou CS4 6 Para criar o arquivo do aplicativo e do instalador, clique no botão Publicar arquivo AIR. Execute Testar filme ou Depurar filme para criar os arquivos SWF e application.xml antes de criar o arquivo AIR. 7 Para instalar o aplicativo, clique duas vezes no arquivo AIR (application.air) na mesma pasta em que salvou seu aplicativo. 8 Clique no botão Instalar no diálogo Instalação do aplicativo. 9 Revise as Preferências da instalação e as Configurações locais e verifique se a caixa de seleção 'Iniciar aplicativo após a instalação' está marcada. Em seguida, clique em Continuar. 10 Clique em Concluir quando a mensagem Instalação concluída for exibida. O aplicativo Hello World é semelhante a esta ilustração: Converter um arquivo FLA em um aplicativo Adobe AIR Você também pode converter um arquivo FLA existente para um aplicativo AIR. Para obter mais informações, consulte “Definição das configurações de publicação do Adobe AIR” na página 13. Se você estiver usando o Flash CS4, consulte Publicação para o Adobe AIR em Como usar o Flash. 13 Capítulo 6: Atualização do Adobe AIR para Flash CS3 Professional A atualização do Adobe® AIR™ para o Adobe® Flash® CS3 Professional aumenta o ambiente de autoria para permitir que você crie, depure e compacte aplicativos Adobe AIR com o Flash. O processo de criação de um aplicativo Adobe AIR consiste na criação de um arquivo FLA do Adobe AIR, na definição das configurações de publicação apropriadas, no desenvolvimento do aplicativo e na criação de arquivos do instalador e do aplicativo que permitirão implantar o aplicativo. Se você estiver usando o Adobe® Flash® CS4 Professional, consulte Publicação no Adobe AIR, em Como usar o Flash, para obter mais informações sobre como criar aplicativos AIR. Para obter mais informações sobre as APIs do Adobe AIR ActionScript®3.0 que podem ser utilizadas no aplicativo, consulte a Referência dos componentes e da linguagem do ActionScript 3.0. Para obter uma lista das APIs do Adobe AIR ActionScript, consulte “Adobe AIR - funcionalidade específica” na página 54. Nota: Para usar classes no pacote air.net, arraste primeiro o componente ServiceMonitorShim do painel Componentes para o painel Biblioteca e, em seguida, adicione a seguinte instrução import ao código ActionScript 3.0: import air.net.*; Criar um arquivo Adobe AIR Você pode criar documentos de Arquivo Flash (Adobe AIR) utilizando a tela de boas-vindas do Flash ou criar um Arquivo Flash (ActionScript 3.0) e convertê-lo em um arquivo Adobe AIR usando a caixa de diálogo Configurações de publicação. No entanto, não é possível criar um arquivo Adobe AIR utilizando a caixa de diálogo Novo documento (Arquivo > Novo). Para obter mais informações sobre a conversão de arquivos FLA em arquivos Adobe AIR, consulte “Definição das configurações de publicação do Adobe AIR” na página 13. 1 Inicie o Flash ou, se já tiver iniciado o Flash, feche quaisquer documentos abertos e volte para a tela de boas-vindas. Nota: Se você desabilitou a tela de boas-vindas do Flash, poderá exibi-la novamente selecionando Editar > Preferências e marcando Tela de boas-vindas na categoria Geral do menu pop-up Ao iniciar. 2 Na tela de boas-vindas, clique em Arquivo Flash (Adobe AIR). Uma mensagem de alerta é exibida para orientá-lo sobre como acessar as configurações do aplicativo Adobe AIR e a documentação da Ajuda. Você pode ignorar essa mensagem de alerta no futuro selecionando Não mostrar novamente, mas não será possível exibi-la posteriormente. Definição das configurações de publicação do Adobe AIR Use as configurações de publicação do Flash para analisar ou alterar as configurações de um arquivo AIR e converter um documento Arquivo Flash (ActionScript 3.0) para um documento Arquivo Flash (Adobe AIR). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 14 Atualização do Adobe AIR para Flash CS3 Professional Exibir configurações de publicação do Adobe AIR 1 Na tela de boas-vindas do Flash, abra um documento Arquivo Flash (Adobe AIR). 2 Selecione Arquivo > Configurações de publicação e clique na aba Flash para ver as configurações de publicação do Adobe Air. O Adobe AIR 1.0 é selecionado automaticamente no menu Versão quando você abre um documento do Adobe AIR. A versão do ActionScript é automaticamente definida para ActionScript 3.0. A configuração Segurança de reprodução local é desativada porque é irrelevante para um arquivo AIR SWF. Se você abrir um arquivo FLA do Flash, poderá convertê-lo para um arquivo AIR do Flash alterando as configurações de publicação. Converter um arquivo FLA do Flash para um arquivo AIR do Flash utilizando a caixa de diálogo Configurações de publicação 1 Execute um dos seguintes procedimentos: • Abra um arquivo FLA existente. • Use a tela de boas-vindas ou selecione Arquivo > Novo para criar um arquivo FLA. 2 Selecione Arquivo > Configurações de publicação. 3 Na aba Flash, selecione Adobe AIR 1.0 no menu pop-up Versão. A entrada de versão do ActionScript fica desabilitada porque ActionScript 3.0 é a única opção para um arquivo AIR. As opções padrão restantes são as mesmas para um arquivo FLA e um arquivo Adobe AIR. 4 Clique no botão Publicar e, em seguida, em OK para fechar a caixa de diálogo Configurações de publicação. O Inspetor de propriedade agora indica que o player de destino é o Adobe AIR 1, quando a ferramenta Seleção é marcada. Nota: Quando você escolher o perfil Adobe AIR 1.0, o Flash adicionará automaticamente o local do arquivo playerglobal.swc do AIR na variável de ambiente Classpath. O arquivo playerglobal.swc do AIR permite que você use as APIs do ActionScript AIR. Contudo, se você alternar do Adobe AIR 1 para o Adobe® Flash® Player 9, o Flash não reverterá automaticamente para o perfil padrão nem irá alterar a configuração de Classpath para usar o arquivo playerglobal.swc para o Flash Player 9. Se você alterar a configuração de publicação do Adobe AIR 1 para o Flash Player 9, deverá alterar o perfil de configuração para Padrão. Para obter informações adicionais sobre a caixa de diálogo Configurações de publicação, consulte Uso do Flash em www.adobe.com/go/learn_fl_using_br. Converter um arquivo FLA do Flash para um aplicativo AIR do Flash utilizando o menu Comandos 1 Abra o arquivo FLA do Flash. 2 Se você estiver abrindo um novo Arquivo Flash (ActionScript 3.0), salve-o. Caso contrário, um aviso será exibido quando iniciar a próxima etapa. 3 Selecione Comandos > AIR - Configurações do aplicativo e do instalador. Uma mensagem de alerta é exibida, perguntando se você deseja converter o arquivo em configurações de publicação do Adobe AIR. 4 Clique em OK para converter o arquivo FLA para as configurações de publicação do Adobe AIR. A caixa de diálogo AIR - Configurações do aplicativo e do instalador é exibida. Para obter informações sobre a caixa de diálogo AIR - Configurações do aplicativo e do instalador, consulte “Criação de arquivos do aplicativo AIR e do instalador” na página 15. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 15 Atualização do Adobe AIR para Flash CS3 Professional Você pode usar os comandos Test Movie, Debug Movie e Create AIR File no arquivo FLA do AIR convertido. Visualizar um aplicativo Adobe AIR Você pode visualizar um arquivo AIR SWF do Flash quando ele for exibido na janela do aplicativo AIR. A visualização é útil quando você quiser ver quais são os aspectos visíveis da aparência do aplicativo sem compactá-lo e instalá-lo. 1 Certifique-se de que você definiu as configurações de publicação no aplicativo Adobe AIR. Para obter mais informações, consulte “Definição das configurações de publicação do Adobe AIR” na página 13. 2 Selecione Controlar > Testar filme ou pressione Ctrl + Enter. Se você ainda não definiu as configurações do aplicativo na caixa de diálogo AIR - Configurações do aplicativo e do instalador, o Flash gera um arquivo de descrição do aplicativo padrão (swfname-app.xml) para você na mesma pasta em que o arquivo SWF está gravado. Se você definir as configurações de aplicativo utilizando a caixa de diálogo AIR - Configurações do aplicativo e do instalador, o arquivo de descrição do aplicativo irá refleti-las. Depurar um aplicativo Adobe AIR O arquivo SWF do Adobe AIR pode ser depurado como um arquivo ActionScript 3.0 SWF do Flash Player 9, exceto para depuração remota. 1 Verifique se você definiu as configurações de publicação do Adobe AIR. 2 Adicione o código ActionScript ao painel Ações (Janela > Ações). Para o teste, você pode simplesmente adicionar uma instrução trace() como a seguinte ao painel Ações, no primeiro quadro da Linha de tempo: trace("My application is running"); 3 Selecione Depurar > Depurar filme ou pressione Ctrl+Shift+Enter. O Flash inicia o depurador do ActionScript e exporta o arquivo SWF com as informações de depuração. Se você ainda não definiu as configurações do aplicativo na caixa de diálogo AIR - Configurações do aplicativo e do instalador, o Flash gera um arquivo de descrição do aplicativo padrão (swfname-app.xml) para você na mesma pasta em que o arquivo SWF está gravado. Se você definir as configurações de aplicativo utilizando a caixa de diálogo AIR - Configurações do aplicativo e do instalador, o arquivo de descrição do aplicativo irá refleti-las. Quando você seleciona Depurar > Depurar filme ou pressiona Ctrl+Shift+Enter para depurar o aplicativo, o Flash exibe um alerta se o seu aplicativo não incluir nenhum código ActionScript. Criação de arquivos do aplicativo AIR e do instalador Depois de concluir seu aplicativo, crie os arquivos do aplicativo AIR e do instalador para implantá-lo. O Adobe AIR adiciona dois itens de menu novos ao menu Comandos de Flash: AIR - Configurações do aplicativo e do instalador e AIR - Criar arquivo AIR. Depois de criar as configurações do aplicativo AIR e do instalador, você pode usar o item AIR-Criar arquivo AIR para recriar o arquivo AIR (.air) com as configurações existentes. Criar arquivos do aplicativo Adobe AIR e do instalador 1 No Flash, abra a página ou o conjunto de páginas que compõe seu aplicativo Adobe AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 16 Atualização do Adobe AIR para Flash CS3 Professional 2 Salve o arquivo FLA do Adobe AIR antes de abrir a caixa de diálogo AIR - Configurações do aplicativo e do instalador. 3 Selecione Comandos > AIR - Configurações do aplicativo e do instalador. 4 Conclua a caixa de diálogo AIR - Configurações do aplicativo e do instalador e clique em Publicar arquivo AIR. Quando você clica no botão Publicar arquivo AIR, os seguintes arquivos são compactados: o arquivo FLA, o arquivo SWF, o arquivo de descrição do aplicativo, os arquivos de ícone do aplicativo e os arquivos listados na caixa de texto Arquivos incluídos. Se você ainda não criou um certificado digital, o Flash exibe a caixa de diálogo Assinatura digital quando você clica no botão Publicar arquivo AIR. A caixa de diálogo AIR - Configurações do aplicativo e do instalador é dividida em duas seções: Configurações do aplicativo e Configurações do instalador. Para obter mais informações sobre as configurações, consulte as seções a seguir. Configurações do aplicativo A seção Configurações do aplicativo da caixa de diálogo AIR - Configurações do aplicativo e do instalador tem as seguintes opções: Nome do arquivo O nome do arquivo principal do aplicativo. O padrão é o nome do arquivo SWF. Nome O nome usado pelo instalador para gerar o nome de arquivo e a pasta do aplicativo. O nome deve conter apenas caracteres válidos para nomes de arquivos ou de pastas. O padrão é o nome do arquivo SWF. Versão Opcional. Especifica o número da versão do aplicativo. O padrão é em branco. ID Identifica o aplicativo com uma ID exclusiva. Você pode alterar a ID padrão se preferir. Não use espaços nem caracteres especiais na ID. Os únicos caracteres válidos são 0-9, a-z, A-Z, . (ponto) e - (traço), os caracteres de 1 a 212 de comprimento. O padrão é com.adobe.example.application_name. Descrição Opcional. Permite digitar uma descrição do aplicativo para ser exibida quando o usuário o instala. O padrão é em branco. Copyright Opcional. Permite digitar um aviso de copyright para ser exibido quando o usuário instala o aplicativo. Estilo da janela Especifica o estilo da janela (ou cromo) que será utilizado na interface de usuário quando o usuário executa o aplicativo no computador. Você pode especificar Cromo do sistema, que se refere ao estilo visual que o sistema operacional usa. Também é possível especificar Cromo personalizado (opaco) ou Cromo personalizado (transparente). Para exibir seu aplicativo sem o cromo do sistema, selecione Nenhum. O Cromo do sistema rodeia o aplicativo com o controle de janelas padrão do sistema operacional. O Cromo personalizado (opaco) elimina o cromo padrão do sistema e permite a você criar um cromo do seu próprio aplicativo. (Você cria o cromo personalizado diretamente no arquivo FLA.) O Cromo personalizado (transparente) é igual ao Cromo personalizado (opaco), mas ele adiciona recursos transparentes às margens da página. Esses recursos servem para janelas de aplicativos que não são quadradas ou retangulares. Ícone Opcional. Permite que você especifique um ícone para o aplicativo. O ícone é mostrado depois que você instala o aplicativo e o executa no Adobe AIR. Você pode especificar quatro tamanhos diferentes de ícones (128, 48, 32 e 16 pixels) para permitir diferentes exibições nas quais os ícones são exibidos. Por exemplo, o ícone pode ser exibido no navegador do arquivo nas exibições em miniatura, detalhes e lado a lado. Ele também pode ser exibido como um ícone de desktop e no título da janela do aplicativo AIR, bem como em outros lugares. O padrão da imagem do ícone é o ícone de aplicativo AIR de amostra, se nenhum outro arquivo de ícone for especificado. Para especificar um ícone, clique no botão Selecionar imagens de ícones na caixa de diálogo AIR - Configurações do aplicativo e do instalador. Na caixa de diálogo Imagens de ícone que é exibida, clique na pasta para cada tamanho de DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 17 Atualização do Adobe AIR para Flash CS3 Professional ícone e selecione o arquivo de ícone que utilizará. Os arquivos devem estar no formato PNG (Portable Network Graphics). A ilustração a seguir mostra a caixa de diálogo Imagens de ícone com os ícones padrão do aplicativo Adobe AIR. Especificação de diferentes tamanhos das imagens de ícone do aplicativo Se você especificar uma imagem, ela deve estar no tamanho exato (128x128, 48x48, 32x32 ou 16x16). Se você não fornecer uma imagem para um tamanho de ícone específico, o Adobe AIR escala one das imagens fornecidas para criar a imagem do ícone que está faltando. Configurações avançadas O botão Configurações na caixa de diálogo AIR - Configurações do aplicativo e do instalador permite especificar configurações avançadas para o arquivo de descrição do aplicativo. Quando você clique no botão Configurações, a caixa de diálogo Configurações avançadas é exibida. A caixa de diálogo Configurações avançadas permite especificar qualquer tipo de arquivo associado que o aplicativo deve suportar. Por exemplo, se você definiu seu aplicativo para ser o aplicativo principal para suportar arquivos HTML, você deverá especificar isso na caixa de texto Tipos de arquivos associados. Também é possível especificar configurações para os seguintes aspectos do aplicativo: • O tamanho e a posição da janela inicial. • A pasta na qual o aplicativo está instalado. • A Pasta de menu do programa na qual o aplicativo ficará. A caixa de diálogo tem as seguintes opções: Tipos de arquivos associados Permite especificar os tipos de arquivos associados aos quais o aplicativo AIR oferece suporte. Clique no botão de adição (+) para adicionar um novo tipo de arquivo à caixa de texto. Clicar no botão de adição (+) exibe a caixa de diálogo Configurações de tipo de arquivo. Clicar no botão de subtração (-) remove um item que está selecionado na caixa de texto. Clicar no botão Lápis exibe a caixa de diálogo Configurações de tipo de arquivo DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 18 Atualização do Adobe AIR para Flash CS3 Professional e permite editar um item selecionado na caixa de texto. Por padrão, os botões de subtração (-) e Lápis estão desativados. A seleção de um item na caixa de texto ativa os botões de subtração (-) e Lápis, permitindo remover ou editar o item. O valor padrão na caixa de texto é Nenhum. Para obter mais informações sobre as configurações de tipo de arquivo para tipos de arquivos associados, consulte “Configurações de tipo de arquivo” na página 18. Configurações da janela inicial Permite especificar as configurações de tamanho e posição para a janela inicial do aplicativo. • Largura: Especifica a largura inicial da janela em pixels. O valor padrão é em branco. • Altura: Especifica a altura inicial da janela em pixels. O valor padrão é em branco. • X: Especifica a posição inicial horizontal da janela em pixels. O valor padrão é em branco. • Y: Especifica a posição inicial vertical da janela em pixels. O valor padrão é em branco. • Largura máxima e altura máxima: Especifica o tamanho máximo da janela em pixels. Os valores padrão são em branco. • Largura mínima e altura mínima: Especifica o tamanho mínimo da janela em pixels. Os valores padrão são em branco. • Maximizável: Permite especificar se o usuário poderá maximizar a janela. Essa opção é selecionada (ou true) por padrão. • Minimizável: Permite especificar se o usuário poderá minimizar a janela. Essa opção é selecionada (ou true) por padrão. • Redimensionável: Permite especificar se o usuário poderá redimensionar a janela. Se essa opção não estiver selecionada, Largura máxima, Altura máxima, Largura mínima e Altura mínima serão desativadas. Essa opção é selecionada (ou true) por padrão. • Visível: Permite especificar se a janela do aplicativo será visível inicialmente. A opção é selecionada (ou true) por padrão. Outras configurações Permite especificar as seguintes informações adicionais sobre a instalação: • Pasta de instalação: especifica a pasta na qual o aplicativo está instalado. • Pasta de menu do programa: especifica o nome da pasta de menu do programa para o aplicativo. • UI atualizada personalizada: especifica o que acontece quando um usuário abre um arquivo AIR para um aplicativo que já está instalado. Por padrão, o AIR exibe uma caixa de diálogo que permite ao usuário atualizar a versão instalada com a versão no arquivo AIR. Se você não quiser que o usuário tome essa decisão e que o aplicativo tenha o controle sobre as atualizações, selecione esta opção. A seleção desta opção substitui o comportamento padrão e fornece ao aplicativo o controle sobre suas atualizações. Para obter informações sobre atualização de um aplicativo AIR programaticamente, consulte “Atualização de aplicativos do AIR” na página 328. Configurações de tipo de arquivo O Flash exibirá a caixa de diálogo Configurações de tipo de arquivo se você clicar no botão de adição (+) ou Lápis na caixa de diálogo Configurações avançadas para adicionar ou editar tipos de arquivo associados para o aplicativo. Os únicos dois campos obrigatórios nessa caixa de diálogo são Nome e Extensão. Se você clicar em OK e esses campos estiverem em branco, o Flash exibirá uma caixa de diálogo de erro. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 19 Atualização do Adobe AIR para Flash CS3 Professional Você pode especificar as seguintes configurações para um tipo de arquivo associado: Nome O nome do tipo de arquivo (por exemplo, linguagem de markup de hipertexto, arquivo de texto ou de exemplo). Extensão A extensão do nome do arquivo (por exemplo, html, txt ou xmpl), até 39 caracteres alfanuméricos básicos (A-Za-z0-9) e sem ponto à esquerda. Descrição Opcional. A descrição de um tipo de arquivo (por exemplo, Arquivo de vídeo da Adobe). Tipo de conteúdo Opcional. Especifica o tipo MIME do arquivo. Configurações do ícone de tipo de arquivo Opcional. Permite especificar um ícone associado ao tipo de arquivo. Você pode especificar quatro tamanhos diferentes de ícone (128x128, 48x48, 32x32 e 16x16 pixels) para permitir diferentes exibições nas quais os ícones são exibidos. Por exemplo, o ícone pode ser exibido no navegador do arquivo nas exibições em miniatura, detalhes e lado a lado. Se você especificar uma imagem, ela deverá ser do tamanho especificado. Se você não especificar um arquivo para um determinado tamanho, o AIR usará a imagem de um tamanho aproximado e a dimensionará para que se ajuste àquela ocorrência. Para especificar um ícone, clique na pasta para o tamanho de ícone e selecione um arquivo de ícone para ser utilizado ou digite o caminho e o nome do arquivo para o arquivo de ícone na caixa de texto próxima ao prompt. O arquivo de ícone deve estar no formato PNG. Após a criação de um novo tipo de arquivo, ele é mostrado na caixa de listagem Tipo de arquivo na caixa de diálogo Configurações avançadas. Configurações do arquivo de descrição do aplicativo As configurações do aplicativo especificadas são salvas no arquivo application_name-app.xml. Contudo, você tem a opção de indicar ao Flash que deseja usar um arquivo personalizado de descrição do aplicativo. Usar arquivo personalizado de descrição do aplicativo Permite navegar até um arquivo personalizado de descrição do aplicativo. Se você selecionar Usar arquivo personalizado de descrição do aplicativo, a seção Configurações do aplicativo da caixa de diálogo ficará desativada. Para especificar o local do arquivo personalizado de descrição do aplicativo, digite-o no campo de texto abaixo de Usar arquivo personalizado de descrição do aplicativo ou clique no ícone de pasta e navegue até o local. Para obter mais informações sobre o arquivo de descrição do aplicativo, consulte “Criação de um arquivo personalizado de descrição do aplicativo” na página 20. Configurações do instalador A segunda seção da caixa de diálogo AIR - Configurações do aplicativo e do instalador contém as configurações de instalação do aplicativo: Assinatura digital Todos os aplicativo Adobe AIR devem estar assinados para serem instalados em outro sistema. Para obter informações sobre atribuição de uma assinatura digital para o aplicativo Adobe AIR do Flash, consulte “Assinatura do aplicativo” na página 21. Destino Especifica onde salvar o arquivo AIR. O local padrão é o diretório em que salvou o arquivo FLA. Clique no ícone de pasta para selecionar um local diferente. O nome do pacote padrão é o nome do aplicativo com a extensão de nome de arquivo .air. Arquivos/Pastas incluídos Especifica os arquivos e as pastas adicionais que estão inclusos no seu aplicativo. Clique no botão de adição (+) para adicionar arquivos e no botão de pasta para adicionar pastas. Para excluir um arquivo ou pasta da lista, selecione o arquivo ou a pasta e clique no botão de subtração (-). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 20 Atualização do Adobe AIR para Flash CS3 Professional Por padrão, o arquivo de descrição do aplicativo e o arquivo SWF principal são adicionados automaticamente à lista de pacotes. A lista de pacotes mostra esses arquivos mesmo se você ainda não tiver publicado o arquivo FLA do Adobe AIR. A lista de pacotes exibe os arquivos e pastas em uma estrutura simples. Os arquivos em uma pasta não são listados, e o caminho completo para os arquivos é mostrado, mas truncado se necessário. Os arquivos de ícone não são incluídos na lista. Quando o Flash compacta os arquivos, ele copie os arquivos de ícone para uma pasta temporária que é relativa ao local do arquivo SWF. O Flash exclui a pasta depois que a compactação estiver concluída. Falha na criação de arquivos do aplicativo e do instalador Falha na criação dos arquivos do aplicativo e do instalador nas seguintes ocorrências: • A string de ID do aplicativo tem um tamanho incorreto ou contém caracteres inválidos. A string de ID do aplicativo pode conter de 1 a 212 caracteres e incluir os seguintes caracteres: 0-9, a-z, A-Z, . (ponto), - (hífen). • Os arquivos não existem na lista do instalador. • Os tamanhos dos arquivos personalizados de ícone estão incorretos. • A pasta de destino do AIR não tem acesso de gravação. • Você não assinou o aplicativo ou não especificou que ele é um aplicativo Adobe AIRI que pode ser assinado posteriormente. Criação de um arquivo personalizado de descrição do aplicativo O arquivo de descrição do aplicativo é um arquivo XML que pode ser editado com um editor de texto. Para criar um arquivo personalizado de descrição do aplicativo, edite os valores para especificar os valores desejados. Os valores padrão são mostrados aqui: • id = com.adobe.example.swfname • fileName = swfname • name = swfname • version = 1.0 • description = blank • copyright = blank • initialWindow • title = name • content = swfname.swf • systemChrome = standard, type = normal • transparent = false • visible = true • icon • image128x128 = icons/AIRApp_128.png • image48x48 = icons/AIRApp_48.png DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 21 Atualização do Adobe AIR para Flash CS3 Professional • image32x32 = icons/AIRApp_32.png • image16x16 = icons/AIRApp_16.png • customUpdateUI = false • allowBrowserInvocation = false Para obter mais informações sobre o arquivo de descrição do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44. Assinatura do aplicativo Todos os aplicativo Adobe AIR devem estar assinados para serem instalados em outro sistema. No entanto, o Flash permite que você crie arquivos do instalador do Adobe AIR não assinados; dessa forma o aplicativo pode ser assinado posteriormente. Esses arquivos do instalador do Adobe AIR não assinados são chamados de pacote AIRI. Esse recurso é útil para os casos em que o certificado está em uma máquina diferente ou a assinatura é tratada separadamente do desenvolvimento do aplicativo. Assinar um aplicativo Adobe AIR com um certificado digital pré-adquirido de uma autoridade de certificação raiz 1 Clique no botão Definição da assinatura digital na caixa de diálogo AIR - Configurações do aplicativo e do instalador. A caixa de diálogo Assinatura digital é aberta. Essa caixa de diálogo tem dois botões de opção que permitem assinar seu aplicativo Adobe AIR com um certificado digital ou preparar um pacote AIRI. Se você assinar seu aplicativo AIR, poderá utilizar um certificado digital concedido por uma autoridade de certificação raiz ou criar um certificado auto-assinado. Um certificado autoassinado é fácil de criar, mas não é tão confiável quanto um certificado concedido por uma autoridade de certificação raiz. Caixa de diálogo Assinatura digital para assinar um aplicativo AIR 2 Selecione um arquivo de certificado no menu pop-up ou clique no botão Procurar para localizar um arquivo de certificado. 3 Selecione o certificado. 4 Digite a senha. 5 Clique em OK. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 22 Atualização do Adobe AIR para Flash CS3 Professional Para obter mais informações sobre o assinatura do aplicativo AIR, consulte “Assinatura digital de um arquivo do AIR” na página 321. Criar um certificado digital auto-assinado 1 Clique no botão Criar. A caixa de diálogo Certificado digital auto-assinado é aberta. 2 Preencha as entradas para Nome do editor, Unidade organizacional, Nome da organização, País, Senha e Confirmar senha. 3 Especifique o tipo de certificado. A opção Tipo refere-se ao nível de segurança que o certificado carrega: 1024-RSA usa uma chave de 1024 bits (menos segura) e 2048-RSA usa uma chave de 2048 bits (mais segura). 4 Salve as informações em um arquivo de certificado preenchendo a entrada Salvar como ou clicando no botão Procurar.para procurar o local da pasta. 5 Clique em OK. 6 Na caixa de diálogo Assinatura digital, digite a senha atribuída na segunda etapa deste procedimento e clique em OK. Depois de definir um certificado digital, o botão Definir muda para um botão Alterar. Para que o Flash lembre da senha usada nesta sessão, clique em Lembrar senha dessa sessão. Se a opção Carimbo de data e hora não estiver marcada quando clicar em OK, uma caixa de diálogo avisará que a instalação do aplicativo falhará quando o certificado digital expirar. Se você clicar em Sim na resposta deste aviso, o carimbo de data e hora será desabilitado. Se você clicar em Não, a opção Carimbo de data e hora será automaticamente selecionada e habilitada. Para obter mais informações sobre a assinatura do aplicativo AIR, consulte “Assinatura digital de um arquivo do AIR” na página 321. Você também pode criar um aplicativo AIRI (AIR Intermediate) sem uma assinatura digital. Entretanto, um usuário não pode instalar o aplicativo em um desktop até que você adicione uma assinatura digital. Preparar um pacote AIRI que será assinado posteriormente ❖ Na caixa de diálogo Assinatura digital, selecione Preparar um pacote AIRI que será assinado posteriormente e clique em OK. O status da assinatura digital é alterado para indicar que você optou por preparar um pacote AIRI que será assinado posteriormente. O botão Definir muda para um botão Alterar. 23 Capítulo 7: Segurança do AIR Esse tópico discute os problemas de segurança que você deve considerar ao desenvolver aplicativos do AIR. Noções básicas de segurança do AIR Os aplicativos do AIR são executados com os mesmos privilégios de usuário dos aplicativos nativos. Em geral, esses privilégios permitem amplo acesso aos recursos do sistema operacional, como leitura e gravação de arquivos, inicialização de aplicativos, desenho na tela e comunicação com a rede. As restrições do sistema operacional aplicadas aos aplicativos nativos, tais como privilégios específicos do usuário, são aplicadas da mesma forma aos aplicativos do AIR. Embora o modelo de segurança do Adobe® AIR™ seja uma evolução do modelo de segurança do Adobe® Flash® Player, o contrato de segurança é diferente daquele aplicado ao conteúdo em um navegador. Esse contrato oferece aos desenvolvedores um meio seguro de funcionalidade mais ampla para experiências enriquecedoras com uma liberdade que seria inadequada para um aplicativo baseado em navegador. Os Aplicativos do AIR são gravados usando o código de bytes compilado (conteúdo SWF) ou o script interpretado (JavaScript, HTML) para que o tempo de execução forneça gerenciamento de memória. Isso minimiza as chances do aplicativo AIR ser afetado pelas vulnerabilidades relacionadas a gerenciamento de memória, como estouro de buffer e corrupção de memória. Essas são algumas das vulnerabilidades mais comuns que afetam os aplicativos de área de trabalho gravados em código nativo. Instalação e atualizações Os aplicativos do AIR são distribuídos por meio de arquivos do instalador do AIR, que usa a extensão air. Quando o Adobe AIR é instalado e um arquivo do instalador do AIR é aberto, o tempo de execução administra o processo de instalação. Nota: Os desenvolvedores podem especificar um nome de versão e de aplicativo e a origem de editor, mas o próprio fluxo de trabalho inicial de instalação do aplicativo não pode ser modificado. Essa restrição é vantajosa para os usuários, pois todos os aplicativos do AIR compartilham um procedimento de instalação consistente, otimizado e seguro, administrado pelo tempo de execução. Se for necessária a personalização do aplicativo, ela poderá ser feita quando o aplicativo for executado pela primeira vez. Local de instalação do tempo de execução Os aplicativos do AIR exigem que, primeiramente, o tempo de execução esteja instalado no computador do usuário, assim como os arquivos SWF exigem que, primeiramente, o plug-in do navegador do Flash Player esteja instalado. O tempo de execução é instalado no seguinte local no computador do usuário: • Mac OS: /Library/Frameworks/ • Windows: C:\Program • Linux: /opt/Adobe Files\Common Files\Adobe AIR AIR/ No Mac OS, para instalar uma versão atualizada de um aplicativo, o usuário deve ter privilégios adequados do sistema para instalar no diretório do aplicativo. No Windows e no Linux, um usuário precisa de privilégios administrativos. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 24 Segurança do AIR O tempo de execução pode ser instalado de duas maneiras: usando o recurso de instalação direta (instalando diretamente do navegador da Web) ou através de instalação manual. Para obter mais informações, consulte “Distribuição, instalação e execução de aplicativos do AIR” na página 312. Instalação direta (tempo de execução e aplicativo) O recurso de instalação direta fornece aos desenvolvedores uma experiência de instalação aprimorada para os usuários que ainda não têm o Adobe AIR instalado. No método de instalação direta, o desenvolvedor cria um arquivo SWF que apresenta o aplicativo de instalação. Quando o usuário clica no arquivo SWF para instalar o aplicativo, ele tenta detectar o tempo de execução. Se o tempo de execução não puder ser detectado, ele será instalado e o tempo de execução será ativado imediatamente com o processo de instalação do aplicativo do desenvolvedor. Instalação manual Se desejar, o usuário pode fazer o download e a instalação manual do tempo de execução antes de abrir o arquivo AIR. Em seguida, o desenvolvedor pode distribuir o arquivo AIR por meios diversos (por exemplo, por e-mail ou link HTML em um site da Web). Quando o arquivo AIR é aberto, o tempo de execução inicia o processo de instalação do aplicativo. Para obter mais informações sobre esse processo, consulte “Distribuição, instalação e execução de aplicativos do AIR” na página 312 Fluxo de instalação do aplicativo O modelo de segurança do AIR permite que os usuários decidam se devem instalar o aplicativo AIR . A experiência de instalação do AIR oferece diversas melhorias sobre as tecnologias de instalação de aplicativo nativo, que tornam essa decisão de confiança mais fácil para usuários: • O tempo de execução fornece uma experiência de instalação consistente em todos os sistemas operacionais, mesmo quando o aplicativo AIR é instalado de um link em um navegador da Web. A maioria das experiências de instalação de aplicativo nativo dependem do navegador ou de outro aplicativo para fornecer informações de segurança, se de fato elas são fornecidas. • A experiência de instalação do aplicativo AIR identifica a fonte do aplicativo e as informações sobre que privilégios estão disponíveis para o aplicativo (se o usuário permitir que a instalação continue). • O tempo de execução administra o processo de instalação de um aplicativo AIR . O aplicativo AIR não pode manipular o processo de instalação que o tempo de execução usa. Em geral, os usuários não devem instalar nenhum aplicativo de área de trabalho vindo de uma fonte não confiável ou que não possa ser verificada. O ônus da prova de segurança de aplicativos nativos é, da mesma forma, verdadeiro para aplicativos do AIR, assim como é para outros aplicativos instaláveis. Destino do aplicativo O diretório de instalação pode ser definido usando uma das duas opções a seguir: 1 O usuário personaliza o destino durante a instalação. O aplicativo é instalado onde o usuário especificar. 2 Se o usuário não alterar o destino da instalação, o aplicativo será instalado no caminho padrão, conforme determinado pelo tempo de execução: • Mac OS: ~/Applications/ • Windows XP e anterior: C:\Program Files\ DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 25 Segurança do AIR • Windows Vista: ~/Apps/ • Linux: /opt/ Se o desenvolvedor especificar a configuração installFolder no arquivo descritor do aplicativo, o aplicativo será instalado em um subcaminho desse diretório. O sistema de arquivos AIR O processo de instalação de aplicativos do AIR copia todos os arquivos que o desenvolvedor incluiu no arquivo do instalador do AIR para o computador local do usuário. O aplicativo instalado é composto de: • Windows: Um diretório contendo todos os arquivos incluídos no arquivo do instalador AIR. O tempo de execução também cria um arquivo exe durante a instalação do aplicativo AIR. • Linux: Um diretório contendo todos os arquivos incluídos no arquivo do instalador do AIR. O tempo de execução também cria um arquivo bin durante a instalação do aplicativo do AIR. • Mac OS: Um arquivo app que contém todo o conteúdo do arquivo do instalador AIR. Ele pode ser inspecionado usando a opção "Mostrar conteúdo do pacote" do Localizador. O tempo de execução cria esse arquivo app como parte da instalação do aplicativo AIR. O aplicativo AIR é executado por: • Windows: Execução do arquivo .exe na pasta de instalação ou um atalho que corresponda a esse arquivo (como um atalho do menu Iniciar ou área de trabalho). • Linux: Iniciar o arquivo .bin na pasta de instalação, selecionar o aplicativo no menu Aplicativos ou executar um alias ou atalho da área de trabalho. • Mac OS: Execução do arquivo .app ou um alias que aponte para ele. O sistema de arquivos do aplicativo também inclui subdiretórios relacionados à função do aplicativo. Por exemplo, as informações gravadas no depósito local criptografado são salvas em um subdiretório do diretório nomeado depois do identificador de aplicativo do aplicativo. Armazenamento de aplicativo AIR Os aplicativos do AIR têm privilégios de gravação em qualquer local do disco rígido do usuário, contudo, os desenvolvedores são incentivados a usar o caminho app-storage:/ para armazenamento local relacionado aos respectivos aplicativos. Os arquivos gravados em app-storage:/ de um aplicativo ficam localizados em um local padrão, dependendo do sistema operacional do usuário: • No Mac OS: o diretório de armazenamento do aplicativo é <appData>/<appId>/Local Store/ onde <appData> é a pasta "preferências do usuário", geralmente: /Users/<user>/Library/Preferences • No Windows: o diretório de armazenamento do aplicativo é <appData>\<appId>\Local Store\ onde <appData> é a "pasta especial" CSIDL_APPDATA do usuário, geralmente: C:\Documents and Settings\<user>\Application Data • No Linux: <appData>/<appID>/Local Store/ onde <appData> é /home/<user>/.appdata Você pode acessar o diretório de armazenamento do aplicativo através da propriedade air.File.applicationStorageDirectory. Você pode acessar o respectivo conteúdo usando o método resolvePath() da classe File. Para obter detalhes, consulte“Trabalho com o sistema de arquivos” na página 106. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 26 Segurança do AIR Atualização do Adobe AIR Quando o usuário instala um aplicativo AIR que requer uma versão atualizada do tempo de execução, ele instala automaticamente o tempo de execução atualizado desejado. Para atualizar o tempo de execução, o usuário deve ter privilégios administrativos no computador. Atualização de aplicativos do AIR O desenvolvimento e a implantação de atualizações de software são alguns dos maiores desafios de segurança que os aplicativos de código nativo enfrentam. A API do AIR oferece um mecanismo para melhorar isso: o método Updater.update() pode ser chamado na inicialização para verificar o local remoto de um arquivo AIR. Se a atualização for adequada, o arquivo AIR é baixado, instalado e o aplicativo reiniciado. Os desenvolvedores podem usar essa classe não apenas para oferecer novas funcionalidades, mas também para responder a vulnerabilidades potenciais de segurança. Nota: Os desenvolvedores podem especificar a versão do aplicativo configurando a propriedade version do arquivo descritor do aplicativo. O AIR não interpreta de maneira nenhuma a string de versão. Portanto, não se presume que a versão "3.0" seja mais atual que a versão "2.0". Depende do desenvolvedor manter versões significativas. Para obter detalhes, consulte “Definição de propriedades no arquivo do descritor do aplicativo” na página 45. Desinstalação de aplicativo AIR O usuário pode desinstalar o aplicativo AIR: • No Windows: Usando o painel Adicionar/Remover programas para remover o aplicativo. • No Mac OS: Excluindo o arquivo app do local de instalação. Remover o aplicativo AIR remove também todos os arquivos no diretório do aplicativo. No entanto, não remove os arquivos que o aplicativo possa ter gravado fora do diretório do aplicativo. Remover aplicativos do AIR não reverte as alterações que o aplicativo AIR fez nos arquivos fora do diretório do aplicativo. Desinstalação do Adobe AIR O AIR pode ser desinstalado: • No Windows: executando Adicionar/Remover programas no Painel de controle, selecionando Adobe AIR e, em seguida, "Remover". • No Mac OS: executando o aplicativo Desinstalador do Adobe AIR no diretório Aplicativos. Configurações de Registro do Windows para administradores No Windows, os administradores podem configurar o computador para impedir (ou permitir) a instalação de aplicativo AIR e atualizações do tempo de execução. Essas configurações estão contidas no Registro do Windows na seguinte chave: HKLM\Software\Policies\Adobe\AIR. Elas incluem o seguinte: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 27 Segurança do AIR Configuração do Registro Descrição AppInstallDisabled Especifica se a instalação e a desinstalação do aplicativo AIR é permitida. Defina como 0 para “permitido,” defina como 1 para “não permitido.” UntrustedAppInstallDisabled Especifica se a instalação de aplicativos do AIR não confiáveis (aplicativos que não incluem certificado confiável) é permitida (consulte “Assinatura digital de um arquivo do AIR” na página 321). Defina como 0 para “permitido,” defina como 1 para “não permitido.” UpdateDisabled Especifica se a atualização do tempo de execução é permitida como uma tarefa de plano de fundo ou como parte de uma instalação explícita. Defina como 0 para “permitido,” defina como 1 para “não permitido.” Caixas de proteção O AIR oferece uma arquitetura de segurança abrangente que define permissões de acordo com cada arquivo em um aplicativo AIR, tanto internos quanto externos. As permissões são concedidas a arquivos de acordo com a respectiva origem, e são atribuídas em agrupamentos lógicos de segurança chamados de caixas de proteção. Sobre as caixas de proteção do aplicativo AIR O modelo de segurança do tempo de execução de caixas de proteção composto pelo modelo de segurança do Flash Player com o acréscimo da caixa de proteção do aplicativo. Os arquivos que não estão na caixa de proteção do aplicativo têm restrições de segurança semelhantes às especificadas pelo modelo de segurança do Flash Player. O tempo de execução usa essas caixas de proteção de segurança para definir o intervalo de dados que o código pode acessar e as operações que ele pode executar. Para manter a segurança local, os arquivos de cada caixa de proteção ficam isolados dos arquivos de outras caixas de proteção. Por exemplo, um arquivo SWF carregado em um aplicativo AIR de uma URL de Internet externa é colocado em uma caixa de proteção remota e, por padrão, não tem permissão para fazer script em arquivos que residem no diretório do aplicativo, que são atribuídos à caixa de proteção do aplicativo. A tabela a seguir descreve os tipos de caixa de proteção: Caixa de proteção Descrição aplicativo O arquivo reside no diretório do aplicativo e opera com o conjunto completo de privilégios do AIR. remoto O arquivo é de uma URL de Internet e opera sob as regras de caixa de proteção baseadas em domínio análogas às regras aplicadas a arquivos remotos do Flash Player. (Há caixas de proteção remotas distintas para cada domínio de rede, como http://www.example.com e https://foo.example.org.) local confiável O arquivo é um arquivo local e o usuário o designou como confiável, usando o Gerenciador de configurações ou um arquivo de configuração confiável do Flash Player. O arquivo pode fazer a leitura de fontes de dados locais e se comunicar com a Internet, mas não tem o conjunto completo de privilégios do AIR. local com rede O arquivo é um arquivo SWF local publicado com uma designação de rede, mas não foi explicitamente confiado pelo usuário. O arquivo pode se comunicar com a Internet mas não pode ler de fontes de dados locais. Essa caixa de proteção só está disponível para conteúdo SWF. local com sistema de arquivos O arquivo é um arquivo de script local que não foi publicado com uma designação de rede e não foi explicitamente confiado pelo usuário. Isso inclui arquivos JavaScript que não foram confiados. O arquivo pode ler de fontes de dados locais, mas não pode se comunicar com a Internet. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 28 Segurança do AIR Este tópico se concentra principalmente na caixa de proteção do aplicativo e no seu relacionamento com as outras caixas de proteção de aplicativo AIR. Os desenvolvedores que usam conteúdo atribuído a outras caixas de proteção devem ler a documentação adicional do modelo de segurança do Flash Player. Consulte o capítulo “Segurança do Flash Player” na documentação Programação do ActionScript 3.0 (http://www.adobe.com/go/flashcs4_prog_as3_security_en) e o Documento Segurança do Flash Player 9 (http://www.adobe.com/go/fp9_0_security_br) ou o Documento Segurança do Flash Player 10 (http://www.adobe.com/go/fp10_0_security_en). A caixa de proteção do aplicativo Quando um aplicativo é instalado, todos os arquivos incluídos no arquivo do instalador do AIR são instalados em um diretório do aplicativo no computador do usuário. Os desenvolvedores podem fazer referência a esse diretório no código por meio do esquema de URL app:/ (consulte “Uso de esquemas de URL do AIR em URLs” na página 306). Todos os arquivos na árvore de diretório do aplicativo são atribuídos à caixa de proteção do aplicativo quando o aplicativo é executado. O conteúdo na caixa de proteção do aplicativo é agraciado com os privilégios completos disponíveis para o aplicativo AIR , incluindo interação com o sistema de arquivos local. Muitos dos aplicativos do AIR só usam esses arquivos instalados localmente para executar o aplicativo. No entanto, os aplicativos do AIR não estão restritos apenas aos arquivos no diretório do aplicativo - eles podem carregar qualquer tipo de arquivo de qualquer fonte. Isso inclui arquivos locais do computador do usuário, bem como arquivos de fontes externas disponíveis, como aqueles em uma rede local ou na Internet. O tipo de arquivo não tem nenhum impacto nas restrições de segurança, os arquivos HTML carregados têm os mesmos privilégios de segurança dos arquivos SWF carregados da mesma fonte. O conteúdo na caixa de proteção de segurança do aplicativo tem acesso as APIs do AIR que o conteúdo de outras caixas de proteção não pode usar. Por exemplo, a propriedade air.NativeApplication.nativeApplication.applicationDescriptor, que retorna o conteúdo do arquivo descritor do aplicativo para o aplicativo, está restrita ao conteúdo na caixa de proteção de segurança do aplicativo. Outro exemplo de API restrita é a classe FileStream, que contém métodos de leitura e gravação no sistema de arquivos local. As APIs do ActionScript disponíveis apenas para o conteúdo na caixa de proteção de segurança do aplicativo são indicadas com o logotipo do AIR na Referência de Linguagem do ActionScript 3.0 para o Adobe AIR. Usar essas APIs em outras caixas de proteção faz com que o tempo de execução lance uma exceção SecurityError. No conteúdo HTML (em um objeto HTMLLoader), todas as APIs JavaScript do AIR (aquelas que estão disponíveis através da propriedade window.runtime ou através do objeto air durante o uso do arquivo AIRAliases.js) estão disponíveis para o conteúdo na caixa de proteção de segurança do aplicativo. O conteúdo HTML de outra caixa de proteção não tem acesso à propriedade window.runtime, portanto, esse conteúdo não pode acessar as APIs do AIR. Restrições de JavaScript e HTML Para conteúdo HTML na caixa de proteção de segurança do aplicativo, há limitações de uso de APIs que possam transformar dinamicamente as strings em código executável, após o código ser carregado. Isso é para evitar que o aplicativo injete inadvertidamente (e execute) código de fontes "não-aplicativo" (como domínios de rede potencialmente inseguros). Um exemplo é o uso da função eval(). Para obter detalhes, consulte “Restrições de código de conteúdo em caixas de proteção distintas” na página 32. Restrições sobre tags img no conteúdo de campo de texto do ActionScript Para evitar possíveis ataques de phishing, as tags img de conteúdo HTML nos objetos TextField do ActionScript são ignoradas no conteúdo SWF na caixa de proteção de segurança do aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 29 Segurança do AIR Restrições em asfunction O conteúdo na caixa de proteção do aplicativo não pode usar o protocolo asfunction do conteúdo HTML nos campos de texto do ActionScript 2.0. Nenhum acesso ao cache persistente entre domínios O conteúdo SWF na caixa de proteção do aplicativo não pode usar o cache entre domínios, um recurso que foi adicionado à Atualização 3 do Flash Player 9. Esse recurso permite que o Flash Player persista em colocar em cache o conteúdo de componente da plataforma Adobe e reutilize-o no conteúdo SWF carregado sob demanda (eliminando a necessidade de recarregar o conteúdo várias vezes). Privilégios de conteúdo em caixas de proteção "não-aplicativo" Os arquivos carregados de um local de rede ou da Internet são atribuídos à caixa de proteção remota. Os arquivos carregados de fora do diretório do aplicativo são atribuídos à caixa de proteção local com sistema de arquivos, local com rede ou local confiável, isso depende de como o arquivo foi criado e se o usuário confiou explicitamente no arquivo por meio do Gerenciador de configurações globais do Flash Player. Para obter detalhes, consulte http://www.macromedia.com/support/documentation/br/flashplayer/help/settings_manager.html. Restrições de JavaScript e HTML Ao contrário do conteúdo na caixa de proteção de segurança do aplicativo, o conteúdo JavaScript em uma caixa de proteção de segurança "não-aplicativo" pode chamar a função eval() para executar código gerado dinamicamente a qualquer momento. No entanto, há restrições para JavaScript em uma caixa de proteção de segurança "não-aplicativo". Isso inclui: • O código JavaScript em uma caixa de proteção "não-aplicativo" não tem acesso ao objeto window.runtime e, portanto, esse código não pode executar APIs do AIR. • Por padrão, o conteúdo em uma caixa de proteção de segurança "não-aplicativo" não pode usar chamadas XMLHttpRequest para carregar dados de outros domínios diferentes do domínio que chama a solicitação. Entretanto, o código do aplicativo pode conceder permissão para que o conteúdo "não-aplicativo" faça isso, definindo um atributo allowCrossdomainXHR no frame ou iframe que o contém. Para obter mais informações, consulte “Script entre conteúdos em domínios distintos” na página 35. • Há restrições na chamada do método window.open() de JavaScript. Para obter detalhes, consulte “Restrições na chamada do método window.open() de JavaScript” na página 35. Para obter detalhes, consulte “Restrições de código de conteúdo em caixas de proteção distintas” na página 32. Restrições no carregamento de elementos CSS, frame, iframe e img O conteúdo HTML nas caixas de proteção de segurança remota (rede) pode carregar apenas conteúdo CSS, frame, iframe e img de domínios remotos (de URLs de rede). O conteúdo HTML nas caixas de proteção local com sistema de arquivos, local com rede ou local confiável só podem carregar conteúdo CSS, frame, iframe e img de caixas de proteção locais (e não de URLs de aplicativo ou de rede). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 30 Segurança do AIR segurança HTML O tempo de execução aplica regras e oferece mecanismos para dominar possíveis vulnerabilidades de segurança em HTML e JavaScript. As mesmas regras são aplicadas se o aplicativo for gravado principalmente em JavaScript ou se você carregar conteúdo HTML e JavaScript em um aplicativo baseado em SWF. Conteúdo na caixa de proteção do aplicativo e a caixa de proteção de segurança "não-aplicativo" (consulte “Caixas de proteção” na página 27) têm privilégios distintos. Ao carregar o conteúdo em um iframe ou frame, o tempo de execução fornece um mecanismo de ponte de caixa de proteção seguro, que permite que o conteúdo frame ou iframe se comunique de maneira segura com o conteúdo na caixa de proteção de segurança do aplicativo. Este tópico descreve a arquitetura de segurança HTML do AIR e como usar os iframes, os frames e a ponte de caixa de proteção para configurar o aplicativo. Para obter mais informações, consulte “Como evitar erros JavaScript relacionados à segurança” na página 235. Visão geral sobre a configuração de aplicativo baseado em HTML Os Frames e iframes oferecem uma estrutura conveniente para organizar conteúdo HTML no AIR. Os frames oferecem um meio de manter a persistência de dados e trabalhar de maneira segura com conteúdo remoto. Como o HTML no AIR retém sua organização normal baseada em página, o ambiente HTML será totalmente atualizado, caso o frame superior do conteúdo HTML "navegue" para uma página diferente. Você pode usar frames e iframes para manter a persistência de dados no AIR, da mesma maneira que em um aplicativo da Web em execução em um navegador. Defina os objetos principais do aplicativo no frame superior e eles persistirão, desde que você não permita que o frame navegue para uma nova página. Use frames ou iframes filhos para carregar e exibir as partes transitórias do aplicativo. (Há diversas maneiras de manter a persistência de dados, que podem ser usadas além de ou em vez de frames. Isso inclui cookies, objetos locais compartilhados, armazenamento local de arquivos, depósito de arquivo criptografado e armazenamento de banco de dados local). Como o HTML no AIR retém sua linha desfocada normal entre o código executável e os dados, o AIR coloca o conteúdo no quadro superior do ambiente HTML, na caixa de proteção do aplicativo. Depois do evento load da página, o AIR restringe quaisquer operações, como eval(), que possam converter uma seqüência de caracteres de texto em um objeto executável. Essa restrição é aplicada mesmo quando o aplicativo não carrega conteúdo remoto. Para permitir que o conteúdo em HTML execute essas operações restritas, você deve usar frames ou iframes para colocar o conteúdo em uma caixa de proteção não-aplicativo. (Executar conteúdo em um quadro filho de uma caixa de proteção pode ser necessário ao usar algumas estruturas do aplicativo JavaScript que dependem da função eval().) Para obter uma lista completa das restrições JavaScript na caixa de proteção do aplicativo, consulte “Restrições de código de conteúdo em caixas de proteção distintas” na página 32. Como o HTML no AIR mantém a capacidade de carregar conteúdo remoto possivelmente inseguro, o AIR aplica a política de mesma origem que impede que o conteúdo de um domínio interaja com o conteúdo de outro domínio. Para permitir a interação entre o conteúdo do aplicativo e o conteúdo de outro domínio, você pode configurar uma ponte para servir como interface entre um frame pai e filho. Configuração de relacionamento pai-filho de caixa de proteção O AIR adiciona os atributos sandboxRoot e documentRoot aos elementos frame e iframe de HTML. Esses atributos permitem tratar o conteúdo do aplicativo como se ele tivesse vindo de outro domínio: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 31 Segurança do AIR Atributo Descrição sandboxRoot A URL que deve ser usada para determinar a caixa de proteção e o domínio em que o conteúdo do frame deve ser colocado. Os esquemas de URL file:, http: ou https: devem ser usados. documentRoot A URL da qual o conteúdo do frame deve ser carregado. Os esquemas de URL file:, app: ou app-storage: devem ser usados. O exemplo a seguir mapeia o conteúdo instalado no subdiretório da caixa de proteção do aplicativo a ser executado na caixa de proteção remota e o domínio www.exemplo.com: <iframe src="ui.html" sandboxRoot="http://www.example.com/local/" documentRoot="app:/sandbox/"> </iframe> Configuração de ponte entre frames pai e filho em caixas de proteção ou domínios distintos O AIR adiciona as propriedades childSandboxBridge e parentSandboxBridge ao objeto window de qualquer frame filho. Essas propriedades permitem definir pontes para servir como interfaces entre um quadro pai e filho. Cada ponte segue em uma direção: childSandboxBridge A propriedade childSandboxBridge permite que o frame filho exponha uma interface para o conteúdo do frame pai. Para expor uma interface, você define a propriedade childSandbox como função ou objeto no frame filho. Em seguida, você pode acessar o objeto ou a função do conteúdo no frame pai. O exemplo a seguir mostra como um script que está sendo executado em um frame filho pode expor um objeto contendo uma função e uma propriedade para o respectivo pai: var interface = {}; interface.calculatePrice = function(){ return .45 + 1.20; } interface.storeID = "abc" window.childSandboxBridge = interface; Se esse conteúdo filho estiver em um iframe com id de "child" atribuída, você poderá acessar a interface do conteúdo pai, lendo a propriedade childSandboxBridge do frame: var childInterface = document.getElementById("child").childSandboxBridge; air.trace(childInterface.calculatePrice()); //traces "1.65" air.trace(childInterface.storeID)); //traces "abc" parentSandboxBridge A propriedade parentSandboxBridge permite que o frame pai exponha uma interface para o conteúdo do frame filho. Para expor uma interface, você define a propriedade parentSandbox do frame filho como função ou objeto no frame pai. Em seguida, você pode acessar o objeto ou a função do conteúdo no frame filho. O exemplo a seguir mostra como um script em execução no frame pai pode expor um objeto contendo uma função save para o filho: var interface = {}; interface.save = function(text){ var saveFile = air.File("app-storage:/save.txt"); //write text to file } document.getElementById("child").parentSandboxBridge = interface; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 32 Segurança do AIR Ao usar essa interface, o conteúdo no frame filho poderá salvar texto em um arquivo chamado save.txt. No entanto, ele não terá nenhum outro acesso ao sistema de arquivos. Em geral, o conteúdo do aplicativo deve expor a interface mais estreita possível para as outras caixas de proteção. O conteúdo filho poderá chamar a função save da seguinte maneira: var textToSave = "A string."; window.parentSandboxBridge.save(textToSave); Se o conteúdo filho tentar definir uma propriedade do objeto parentSandboxBridge, o tempo de execução lançará uma exceção SecurityError. Se o conteúdo pai tentar definir uma propriedade do objeto childSandboxBridge, o tempo de execução lançará uma exceção SecurityError. Restrições de código de conteúdo em caixas de proteção distintas Como discutido na introdução deste tópico, “segurança HTML” na página 30, o tempo de execução aplica regras e fornece mecanismos para dominar possíveis vulnerabilidades de segurança em HTML e JavaScript. Este tópico lista essas restrições. Se o código tentar chamar essas APIs restritas, o tempo de execução lançará um erro com a mensagem "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo". Para obter mais informações, consulte “Como evitar erros JavaScript relacionados à segurança” na página 235. Restrições sobre o uso da função eval() de JavaScript e técnicas semelhantes Para conteúdo HTML na caixa de proteção de segurança do aplicativo há limitações no uso das APIs que podem transformar dinamicamente as strings em código executável após o carregamento do código (após o evento onload do elemento body ter sido despachado e o término de execução da função do manipulador onload). Isso é para evitar que o aplicativo injete inadvertidamente (e execute) código de fontes "não-aplicativo" (como domínios de rede potencialmente inseguros). Por exemplo, se o aplicativo usa strings de dados de uma fonte remota para gravar na propriedade innerHTML de um elemento DOM, a string pode incluir o código (JavaScript) executável que pode executar operações inseguras. No entanto, enquanto o conteúdo estiver carregando, não há risco de inserir strings remotas no DOM. Uma restrição está no uso da função eval() de JavaScript. Após o código na caixa de proteção do aplicativo tiver sido carregado e após o processamento do manipulador de eventos onload, você só poderá usar a função eval() de forma limitada. As seguintes regras se aplicam ao uso da função eval()após o código ter sido carregado da caixa de proteção de segurança do aplicativo: • São permitidas expressões que envolvem literais. Por exemplo: eval("null"); eval("3 + .14"); eval("'foo'"); • As literais de objeto são permitidos da seguinte maneira: { prop1: val1, prop2: val2 } • As opções setter/getters de literal de objeto são proibidas, conforme segue: { get prop1() { ... }, set prop1(v) { ... } } • As literais de matriz são permitidas da seguinte maneira: [ val1, val2, val3 ] • Expressões que envolvem leituras de propriedades são proibidas, conforme segue: a.b.c DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 33 Segurança do AIR • A chamada de função é proibida. • Definições de função são proibidas. • A configuração de qualquer propriedade é proibida. • As literais de função são proibidas. No entanto, enquanto o código estiver sendo carregado, antes do evento onload e durante a execução da função do manipulador de eventos onload, essas restrições não serão aplicadas ao conteúdo na caixa de proteção de segurança do aplicativo. Por exemplo, após o código ser carregado, o código a seguir resultará no lançamento de uma exceção pelo tempo de execução. eval("alert(44)"); eval("myFunction(44)"); eval("NativeApplication.applicationID"); O código gerado dinamicamente, como o que é feito durante a chamada da função eval(), representaria um risco à segurança se permitido na caixa de proteção do aplicativo. Por exemplo, um aplicativo pode executar inadvertidamente uma string carregada de um domínio de rede e essa string pode conter código mal-intencionado. Por exemplo, esse pode ser um código de exclusão ou alteração de arquivos no computador do usuário. Ou pode ser um código que informa o conteúdo de um arquivo local para um domínio de rede não confiável. As formas de gerar código dinâmico são as seguintes: • Chamando a função eval(). • Uso de propriedades innerHTML ou funções DOM para inserir tags de script que carregam um script de fora do diretório do aplicativo. • Uso de propriedades innerHTML ou funções DOM para inserir tags de scripts com código inline (em vez de carregar um script através do atributo src). • Configuração do atributo src para que a tag de script carregue um arquivo JavaScript que está fora do diretório do aplicativo. • Uso de esquema de URL javascript (como em href="javascript:alert('Test')"). • Uso da função setInterval() ou setTimout() em que o primeiro parâmetro (que define a função para ser executada de forma assíncrona) é uma string (a ser avaliada) em vez de um nome de função (como em setTimeout('x = 4', 1000)). • Chamada de document.write() ou document.writeln(). O código na caixa de proteção de segurança do aplicativo só pode usar esses métodos enquanto o conteúdo estiver sendo carregado. Essas restrições não impedem o uso de eval() com literais do objeto JSON. Isso permite que o conteúdo do aplicativo trabalhe com a biblioteca JavaScript JSON. No entanto, você não poderá usar código JSON sobrecarregado (com manipuladores de eventos) Em outras estruturas Ajax e bibliotecas de código JavaScript, certifique-se de que o código na estrutura ou biblioteca funciona dentro dessas restrições em código gerado dinamicamente. Se não funcionarem, inclua algum conteúdo que use a estrutura ou biblioteca em uma caixa de proteção de segurança "não-aplicativo". Para obter detalhes, consulte “Privilégios de conteúdo em caixas de proteção "não-aplicativo"” na página 29 e “Script entre conteúdo de aplicativo e "não-aplicativo"” na página 40. O Adobe mantém uma lista das estruturas Ajax conhecidas por oferecer suporte à caixa de proteção de segurança do aplicativo, em http://www.adobe.com/products/air/develop/ajax/features/. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 34 Segurança do AIR Ao contrário do conteúdo na caixa de proteção de segurança do aplicativo, o conteúdo JavaScript em uma caixa de proteção de segurança "não-aplicativo" pode chamar a função eval() para executar código gerado dinamicamente a qualquer momento. Restrições de acesso às APIs do AIR (para caixas de proteção "não-aplicativo") O código JavaScript em uma caixa de proteção "não-aplicativo" não tem acesso ao objeto window.runtime e, portanto, esse código não pode executar APIs do AIR. Se o conteúdo em uma caixa de proteção de segurança "não-aplicativo" chamar o código a seguir, o aplicativo lançará uma exceção TypeError: try { window.runtime.flash.system.NativeApplication.nativeApplication.exit(); } catch (e) { alert(e); } O tipo de exceção é TypeError (valor indefinido), porque o conteúdo na caixa de proteção "não-aplicativo" não reconhece o objeto window.runtime, portanto, ele é considerado como valor indefinido. Você pode expor a funcionalidade de tempo de execução ao conteúdo em uma caixa de proteção "não-aplicativo" usando uma ponte de script. Para obter detalhes, consulte “Script entre conteúdo de aplicativo e "não-aplicativo"” na página 40. Restrições no uso de chamadas XMLHttpRequest O conteúdo HTML na caixa de proteção de segurança do aplicativo não pode usar os métodos XMLHttpRequest síncronos para carregar dados de fora da caixa de proteção do aplicativo enquanto o conteúdo HTML estiver sendo carregado e durante o evento onLoad. Por padrão, o conteúdo HTML nas caixas de proteção de segurança "não-aplicativo" não têm permissão para usar o objeto XMLHttpRequest de JavaScript para carregar dados de outros domínios que não o domínio que está chamando a solicitação. A tag frame ou iframe pode incluir um atributo allowcrosscomainxhr. Configurar esse atributo como qualquer valor diferente de "null" permite que o conteúdo no frame ou iframe use o objetoXMLHttpRequest de Javascript para carregar dados de outros domínios que não sejam o domínio do código que está chamando a solicitação: <iframe id="UI" src="http://example.com/ui.html" sandboxRoot="http://example.com/" allowcrossDomainxhr="true" documentRoot="app:/"> </iframe> Para obter mais informações, consulte “Script entre conteúdos em domínios distintos” na página 35. Restrições no carregamento de elementos CSS, frame, iframe e img (para conteúdo em caixas de proteção "não-aplicativo") O conteúdo HTML nas caixas de proteção de segurança remota (rede) pode carregar apenas conteúdo CSS, frame, iframe e img de caixas de proteção remotas (de URLs de rede). O conteúdo HTML nas caixas de proteção local com sistema de arquivos, local com rede ou local confiável só podem carregar conteúdo CSS, frame, iframe e img de caixas de proteção locais (e não de caixas de proteção de aplicativo ou remotas). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 35 Segurança do AIR Restrições na chamada do método window.open() de JavaScript Se a janela criada através de uma chamada para o método window.open() de JavaScript exibir conteúdo de uma caixa de proteção de segurança "não-aplicativo", o título da janela iniciará com o título da janela principal (inicializada), seguido pelo caractere dois pontos. Você não pode usar código para remover da tela essa parte do título da janela. O conteúdo nas caixas de proteção de segurança "não-aplicativo" só consegue chamar com êxito o método window.open() de JavaScript em resposta a um evento acionado pelo mouse do usuário ou pela interação do teclado. Isso evita que o conteúdo "não-aplicativo" crie janelas que possam ser usadas de maneira enganosa (por exemplo, em ataques de phishing). Além disso, o manipulador de eventos do evento de mouse ou teclado não pode configurar o método window.open() para ser executado após um atraso (por exemplo, chamando a função setTimeout()). O conteúdo nas caixas de proteção remotas (rede) só podem usar o método window.open() para abrir o conteúdo nas caixas de proteção de rede remota. Ele não pode usar o método window.open() para abrir o conteúdo das caixas de proteção locais ou do aplicativo. O conteúdo nas caixas de proteção local com sistema de arquivos, local com rede ou local confiável (consulte “Caixas de proteção” na página 27 ) só pode usar o método window.open() para abrir o conteúdo nas caixas de proteção locais. Ele não pode usar o método window.open() para abrir o conteúdo das caixas de proteção remotas ou do aplicativo. Erros na chamada de código restrito Se você chamar um código com uso restrito em uma caixa de proteção, devido a essas restrições de segurança, o tempo de execução despachará um erro de JavaScript: "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo." Para obter mais informações, consulte “Como evitar erros JavaScript relacionados à segurança” na página 235. Proteção da caixa de proteção ao carregar conteúdo HTML de uma seqüência de caracteres O método loadString() da classe HTMLLoader permite criar conteúdo HTML no tempo de execução. No entanto, os dados usados como conteúdo HTML podem ser corrompidos se forem carregados de uma fonte de Internet insegura. Por esse motivo, por padrão, o HTML criado com o método loadString() não é colocado na caixa de proteção do aplicativo e não tem acesso às APIs do AIR. Entretanto, você pode definir a propriedade placeLoadStringContentInApplicationSandbox de um objeto HTMLLoader como true para inserir o HTML criado usando o método loadString() na caixa de proteção do aplicativo. Para obter mais informações, consulte “Carregamento de conteúdo HTML de uma string” na página 233. Script entre conteúdos em domínios distintos Aplicativos do AIR recebem privilégios especiais quando são instalados. É fundamental que os mesmos privilégios não vazem para outro conteúdo, incluindo arquivos remotos e arquivos locais que não fazem parte do aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 36 Segurança do AIR Sobre a ponte de caixa de proteção do AIR Normalmente, o conteúdo de outros domínios não pode chamar scripts de outros domínios. Para proteger os aplicativos do AIR de vazamentos acidentais de informações privilegiadas ou de controle, as restrições a seguir são colocadas no conteúdo na caixa de proteção de segurança do aplicativo (conteúdo instalado com o aplicativo): • O código na caixa de proteção de segurança do aplicativo não pode permitir que outras caixas de proteção chamem o método Security.allowDomain(). Chamar esse método de uma caixa de proteção de segurança do aplicativo gerará um erro. • Evita-se importar conteúdo "não-aplicativo" da caixa de proteção do aplicativo, definindo a propriedade LoaderContext.securityDomain ou LoaderContext.applicationDomain. Ainda há casos em que o aplicativo principal do AIR requer que o conteúdo de um domínio remoto tenha acesso controlado a scripts no aplicativo principal do AIR ou vice-versa. Para fazer isso, o tempo de execução oferece o mecanismo ponte de caixa de proteção, que serve como gateway entre as duas caixas de proteção. A ponte de caixa de proteção pode oferecer interação explícita entre as caixas de proteção de segurança do aplicativo e remota. A ponte de caixa de proteção expõe dois objetos que os scripts, carregados e em carregamento, podem acessar: • O objeto parentSandboxBridge permite carregar propriedades e funções de exposição de conteúdo para scripts no conteúdo carregado. • O objeto childSandboxBridge permite que o conteúdo carregado exponha propriedades e funções para scripts no conteúdo que está em carregamento. Os objetos expostos através da ponte de caixa de proteção são passadas por valor e não por referência. Todos os dados são serializados. Isso significa que os objetos expostos de um lado da ponte não podem ser definidos pelo outro lado da ponte e que os objetos expostos são todos sem categoria. Além disso, você pode expor objetos e funções simples, você não pode expor objetos complexos. Se o conteúdo filho tentar definir uma propriedade do objeto parentSandboxBridge, o tempo de execução lançará uma exceção SecurityError. Da mesma forma, se o conteúdo pai tentar definir uma propriedade do objeto childSandboxBridge, o tempo de execução lançará uma exceção SecurityError. Exemplo de ponte de caixa de proteção (SWF) Suponhamos que um aplicativo de armazenamento de música do AIR deseja permitir que arquivos remotos SWF transmitam preços de álbuns, mas não deseja que o arquivo remoto SWF divulgue se é preço de venda. Para fazer isso, a classe StoreAPI oferece um método para adquirir o preço, mas ocultar o preço de venda. Em seguida, é atribuída uma ocorrência dessa classe StoreAPI à propriedade parentSandboxBridge do objeto LoaderInfo do objeto Loader que carrega o SWF remoto. A seguir está o código para armazenamento de música do AIR: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 37 Segurança do AIR <?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" title="Music Store" creationComplete="initApp()"> <mx:Script> import flash.display.Loader; import flash.net.URLRequest; private var child:Loader; private var isSale:Boolean = false; private function initApp():void { var request:URLRequest = new URLRequest("http://[www.yourdomain.com]/PriceQuoter.swf") child = new Loader(); child.contentLoaderInfo.parentSandboxBridge = new StoreAPI(this); child.load(request); container.addChild(child); } public function getRegularAlbumPrice():String { return "$11.99"; } public function getSaleAlbumPrice():String { return "$9.99"; } public function getAlbumPrice():String { if(isSale) { return getSaleAlbumPrice(); } else { return getRegularAlbumPrice(); } } </mx:Script> <mx:UIComponent id="container" /> </mx:WindowedApplication> O objeto StoreAPI chama o aplicativo principal para recuperar o preço regular do álbum, mas retorna "Não disponível" quando o método getSaleAlbumPrice() é chamado. O código a seguir define a classe StoreAPI: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 38 Segurança do AIR public class StoreAPI { private static var musicStore:Object; public function StoreAPI(musicStore:Object) { this.musicStore = musicStore; } public function getRegularAlbumPrice():String { return musicStore.getRegularAlbumPrice(); } public function getSaleAlbumPrice():String { return "Not available"; } public function getAlbumPrice():String { return musicStore.getRegularAlbumPrice(); } } O seguinte código representa um exemplo de um arquivo PriceQuoter SWF que informa o preço da loja, mas não pode informar o preço de venda: package { import flash.display.Sprite; import flash.system.Security; import flash.text.*; public class PriceQuoter extends Sprite { private var storeRequester:Object; public function PriceQuoter() { trace("Initializing child SWF"); trace("Child sandbox: " + Security.sandboxType); storeRequester = loaderInfo.parentSandboxBridge; var tf:TextField = new TextField(); tf.autoSize = TextFieldAutoSize.LEFT; addChild(tf); tf.appendText("Store price of album is: " + storeRequester.getAlbumPrice()); tf.appendText("\n"); tf.appendText("Sale price of album is: " + storeRequester.getSaleAlbumPrice()); } } } Exemplo de ponte de caixa de proteção (HTML) No conteúdo HTML, as propriedades parentSandboxBridge e childSandboxBridge são adicionados ao objeto de janela de JavaScript de um documento filho. Para obter um exemplo sobre como definir funções de ponte em conteúdo HTML, consulte “Configuração de interface de ponte de caixa de proteção” na página 249. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 39 Segurança do AIR Limitação de exposição de API Ao expor pontes de caixa de proteção, é importante expor APIs de alto nível que limitem o grau em que podem ser abusadas. Lembre-se de que o conteúdo que chama a implementação da ponte pode estar comprometido (por exemplo, através de uma injeção de código). Portanto, por exemplo, expor um método readFile(path:String) (que lê o conteúdo de um arquivo arbitrário) através de uma ponte, estará vulnerável a abusos. Talvez seja melhor expor uma API readApplicationSetting() que não siga um caminho e leia um arquivo específico. A abordagem mais semântica limita o dano que o aplicativo pode causar, já que parte dele está comprometida. Consulte também “Conteúdo entre scripts em caixas de proteção de segurança distintas” na página 248 “A caixa de proteção do aplicativo” na página 28 “Privilégios de conteúdo em caixas de proteção "não-aplicativo"” na página 29 Gravação em disco Os aplicativos em execução em um navegador da Web só têm interação limitada com o sistema de arquivos local do usuário. Os navegadores da Web implementam políticas de segurança que garantem que o computador do usuário não pode ser comprometido como resultado do carregamento de conteúdo da Web. Por exemplo, os arquivos SWF executados por meio do Flash Player em um navegador não podem interagir diretamente com os arquivos existentes no computador do usuário. Os objetos compartilhados e os cookies podem ser gravados no computador do usuário com a finalidade de manter as preferências do usuário e outros dados, mas esse é o limite de interação do sistema de arquivos. Como os aplicativos do AIR são instalados de forma nativa, eles têm contratos de segurança diferentes, um dos quais inclui a capacidade de leitura e gravação no sistema de arquivos local. Essa liberdade resulta em bastante responsabilidade para os desenvolvedores A falta de segurança acidental do aplicativo coloca em risco não apenas a funcionalidade do aplicativo, mas também a integridade do computador do usuário. Por esse motivo, os desenvolvedores devem ler as “Práticas recomendadas de segurança para desenvolvedores” na página 41. Os desenvolvedores do AIR podem acessar e gravar arquivos no sistema de arquivos local usando diversas convenções de esquema de URL: esquema de URL Descrição app:/ Um alias para o diretório do aplicativo. Aos arquivos acessados desse caminho são atribuídas caixas de proteção do aplicativo e eles têm todos os privilégios concedidos pelo tempo de execução. app-storage:/ Um alias para o diretório de armazenamento local, padronizado pelo tempo de execução. Aos arquivos acessados desse caminho é atribuída uma caixa de proteção "não-aplicativo". file:/// Um alias que representa a raiz do disco rígido do usuário. Ao arquivo acessado desse caminho é atribuída uma caixa de proteção do aplicativo, se o arquivo estiver no diretório do aplicativo e, caso contrário, uma caixa de proteção "não-aplicativo". Nota: Os aplicativos do AIR não podem modificar o conteúdo que usa o app: esquema de URL. Além disso, o diretório do aplicativo pode ser lido somente devido às configurações do administrador. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 40 Segurança do AIR A menos que haja restrições do administrador para o computador do usuário, os aplicativos do AIR têm privilégio de gravação em qualquer local no disco rígido do usuário, Recomenda-se que os desenvolvedores usem o caminho appstorage:/ para armazenamento local em relação ao aplicativo. Os arquivos gravados em app-storage:/ de um aplicativo são colocados em um local padrão: • No Mac OS: o diretório de armazenamento do aplicativo é <appData>/<appId>/Local Store/ onde <appData> é a pasta Preferências do usuário, que é normalmente /Users/<user>/Library/Preferences • No Windows: o diretório de armazenamento do aplicativo é <appData>\<appId>\Local Store\ onde <appData> é a pasta especial CSIDL_APPDATA do usuário, que é normalmente C:\Documents and Settings\<userName>\Application Data • No Linux: <appData>/<appID>/Local Store/ onde <appData> é /home/<user>/.appdata Se o aplicativo for desenvolvido para interagir com os arquivos existentes no sistema de arquivos do usuário, certifique-se de ler as “Práticas recomendadas de segurança para desenvolvedores” na página 41. Trabalho seguro com conteúdo não confiável O conteúdo não atribuído à caixa de proteção do aplicativo pode oferecer funcionalidade adicional de script ao aplicativo, mas somente se ele atender aos critérios de segurança do tempo de execução. Este tópico explica o contrato de segurança do AIR com conteúdo "não-aplicativo". Security.allowDomain() Os aplicativos do AIR restringem o acesso de script de conteúdo "não-aplicativo" com mais rigor do que o plug-in de navegador do Flash Player restringe o acesso de script de conteúdo não confiável. Por exemplo, no Flash Player, no navegador, quando um arquivo SWF atribuído à caixa de proteção local-trusted chama o método System.allowDomain(), todos os SWF carregados do domínio especificado receberão acesso de script. Não é permitida a abordagem análoga do conteúdo do aplicativo nos aplicativos do AIR, já que ela concederia acesso excesso não razoável ao arquivo "não-aplicativo" no sistema de arquivos do usuário. Os arquivos remotos não podem acessar diretamente a caixa de proteção do aplicativo, independentemente das chamadas para o métodoSecurity.allowDomain(). Script entre conteúdo de aplicativo e "não-aplicativo" Os aplicativos do AIR que fazem script entre conteúdo aplicativo e "não-aplicativo" têm organizações de segurança mais complexas. Os arquivos que não estão na caixa de proteção do aplicativo só têm permissão para acessar propriedades e métodos de aplicativos na caixa de proteção do aplicativo por meio do uso de uma ponte de caixa de proteção. A ponte da caixa de proteção atua como gateway entre o conteúdo do aplicativo e "não-aplicativo", oferecendo interação explícita entre os dois arquivos. Quando usadas corretamente, as pontes de caixa de proteção oferecem uma camada extra de segurança, impedindo o conteúdo "não-aplicativo" de acessar as referências de objeto que fazem parte do conteúdo do aplicativo. O benefício das pontes de caixa de proteção é ilustrado melhor através do exemplo. Suponhamos que um aplicativo de armazenamento de música do AIR deseja fornecer uma API para anunciantes que desejam criar seus próprios arquivos SWF, com o qual o aplicativo de armazenamento poderá se comunicar em seguida. A loja deseja fornecer aos anunciantes métodos de pesquisa de artistas e CDs, mas também deseja isolar alguns métodos e propriedades do arquivo SWF terceirizado, por motivos de segurança. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 41 Segurança do AIR A ponte de caixa de proteção pode propiciar essa funcionalidade. Por padrão, o conteúdo carregado externamente em um aplicativo AIR em tempo de execução não tem acesso a nenhum método ou propriedade no aplicativo principal. Com a implementação da ponte de caixa de proteção personalizada, o desenvolvedor pode fornecer serviços ao conteúdo remoto sem expor esses métodos ou propriedades. Considere a ponte de caixa de proteção como um caminho entre o conteúdo confiável e o não confiável, oferecendo comunicação entre o conteúdo carregado e o do carregador sem expor as referências do objeto. Para obter mais informações sobre como usar pontes de caixa de proteção de forma segura, consulte “Script entre conteúdos em domínios distintos” na página 35. Proteção contra conteúdo SWF inseguro gerado dinamicamente. O método Loader.loadBytes() oferece uma maneira de o aplicativo gerar conteúdo SWF de uma matriz de bytes. No entanto, ataques de injeção em dados carregados de fontes remotas podem causar dano grave ao carregar o conteúdo. Isso é particularmente verdadeiro ao carregar dados na caixa de proteção do aplicativo, onde o conteúdo SWF gerado pode acessar o conjunto completo de APIs do AIR. Há usos válidos para a utilização do método loadBytes() sem gerar um código SWF executável. Você pode usar o método loadBytes() para gerar dados de imagem para controlar o tempo de exibição de imagem, por exemplo. Há também usos válidos que dependem do código de execução, como a criação dinâmica de conteúdo SWF para reprodução de áudio. No AIR, por padrão, o método loadBytes()não permite carregar conteúdo SWF, ele só permite carregar conteúdo de imagem. No AIR, a propriedade loaderContext do método loadBytes() tem uma propriedade allowLoadBytesCodeExecution, que você pode definir como true para permitir explicitamente que o aplicativo use loadBytes() para carregar o conteúdo SWF executável. O código a seguir mostra como usar esse recurso: var loader:Loader = new Loader(); var loaderContext:LoaderContext = new LoaderContext(); loaderContext.allowLoadBytesCodeExecution = true; loader.loadBytes(bytes, loaderContext); Se você chamar loadBytes() para carregar conteúdo SWF e a propriedade allowLoadBytesCodeExecution do objeto LoaderContext estiver definida como false (o padrão), o objeto Loader lançará uma exceção SecurityError. Nota: Em um lançamento futuro do Adobe AIR, essa API pode ser alterada. Quando isso ocorre, talvez seja necessário recompilar o conteúdo que usa a propriedade allowLoadBytesCodeExecution da classe LoaderContext. Práticas recomendadas de segurança para desenvolvedores Embora os aplicativos do AIR sejam criados usando tecnologias da Web, é importante para os desenvolvedores observar que eles não trabalham na caixa de proteção de segurança do navegador. Isso significa que é possível criar aplicativos do AIR que podem danificar o sistema local de maneira intencional ou não intencional. O AIR tenta minimizar esse risco, mais ainda há formas em que as vulnerabilidades podem ser introduzidas. Este tópico cobre faltas de segurança potenciais importantes. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 42 Segurança do AIR Risco de importar arquivos para a caixa de proteção de segurança do aplicativo Os arquivos existentes no diretório do aplicativo estão atribuídos à caixa de proteção do aplicativo e têm privilégios completos de tempo de execução. Recomenda-se aos aplicativos que gravam no sistema de arquivos local gravar no app-storage:/. Esse diretório está separado dos arquivos do aplicativo no computador do usuário, por isso os arquivos não estão atribuídos na caixa de proteção do aplicativo e representam risco reduzido de segurança. Recomenda-se aos desenvolvedores que considerem o seguinte: • Somente incluir um arquivo em um arquivo do AIR (no aplicativo instalado) se for necessário. • Somente incluir um arquivo em um arquivo do AIR (no aplicativo instalado) se o respectivo comportamento for completamente compreensível e confiável. • Não grave nem modifique conteúdo no diretório do aplicativo. O tempo de execução impede que aplicativos gravem ou modifiquem arquivos e diretórios que usam o esquema de URL app:/, lançando uma exceção SecurityError. • Não use dados de uma fonte de rede como parâmetros de métodos da API do AIR que possam conduzir a execução de código. Isso inclui o uso do método Loader.loadBytes() e a função eval() de JavaScript. Risco de uso de fonte externa para determinar caminhos O aplicativo AIR pode estar com o uso de dados ou conteúdo externo comprometido. Por esse motivo, tenha cuidado especial ao usar dados da rede ou do sistema de arquivos. O ônus da confiança, depende em última análise do desenvolvedor e das conexões de rede que eles fazem, mas carregar dados externos é inerentemente arriscado e não deve ser usado em inserções de operações confidenciais. Recomenda-se aos desenvolvedores o seguinte: • Usar dados de uma fonte de rede para determinar o nome de arquivo • Usar dados de uma fonte de rede para construir uma URL que o aplicativo use para enviar informações particulares O risco de usar, armazenar ou transmitir credenciais não seguras Armazenar credenciais do usuário no sistema de arquivos local do usuário introduz inerentemente o risco de que essas credenciais possam estar comprometidas. Recomenda-se aos desenvolvedores considerar o seguinte: • Se credenciais devem ser armazenadas localmente, criptografe as credenciais ao gravá-las no sistema de arquivos local. O tempo de execução oferece um armazenamento criptografado exclusivo para cada aplicativo instalado, através da classe EncryptedLocalStore. Para obter detalhes, consulte “Armazenamento de dados criptografados” na página 215. • Não transmita credenciais do usuário não criptografadas em uma fonte de rede, a menos que essa fonte seja confiável. • Nunca especifique uma senha padrão na criação de credencial: deixe que os usuários criem suas próprias senhas. Usuários que mantêm o padrão inalterado expõem as respectivas credenciais ao invasor que já conhece a senha padrão. Risco de um ataque de downgrade Durante a instalação do aplicativo, o tempo de execução certifica-se de que não haja uma versão do aplicativo instalada atualmente. Se o aplicativo já estiver instalado, o tempo de execução compara a string da versão em relação à versão que está sendo instalada. Se essa string for diferente, o usuário poderá optar por atualizar a instalação. O tempo de execução não garante que a versão instalada recentemente seja mais recente que a versão anterior, apenas que seja diferente. O invasor pode distribuir uma versão anterior para o usuário, para contornar uma falha de segurança. Por DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 43 Segurança do AIR esse motivo, recomenda-se que o desenvolvedor verifique as versões quando o aplicativo for executado. É uma boa idéia fazer com que os aplicativos verifiquem a rede em busca de atualizações necessárias. Dessa maneira, mesmo se um invasor fizer com que o usuário execute uma versão anterior, essa versão anterior irá reconhecer que é necessário atualizar. Além disso, usar um esquema de versão bem-definido no aplicativo torna mais difícil enganar os usuários para que instalem uma versão desatualizada. Para obter detalhes sobre como fornecer versões de aplicativo, consulte “Definição de propriedades no arquivo do descritor do aplicativo” na página 45. Assinatura de código Todos os arquivos do instalador do AIR são obrigatórios para assinatura de código. A assinatura de código é um processo criptográfico para confirmar que a origem especificada do software é precisa. Os aplicativos do AIR podem ser assinados vinculando um certificado de uma autoridade de certificado externa (CA) ou criando o seu próprio certificado Recomenda-se fortemente um certificado comercial de uma CA bem conhecida que ofereça segurança a seus usuários de que estão instalando o aplicativo original e não uma falsificação. No entanto, os certificados autoassinados podem ser criados usando adt do SDK ou usando Flash, Flex Builder ou outro aplicativo que use adt para geração de certificados. Certificados auto-assinados não oferecem nenhuma segurança de que o aplicativo que está sendo instalado seja genuíno. Para obter mais informações sobre como assinar digitalmente aplicativos do AIR , consulte “Assinatura digital de um arquivo do AIR” na página 321 e “Criação de um aplicativo do AIR usando as ferramentas de linha de comando” na página 355. 44 Capítulo 8: Configuração de propriedades do aplicativo do AIR Com exceção de todos os arquivos e outros ativos que formam um aplicativo do AIR, cada aplicativo do AIR requer um arquivo do descritor do aplicativo. O arquivo do descritor do aplicativo é um arquivo XML que define as propriedades básicas do aplicativo. Ao desenvolver aplicativos do AIR usando a atualização do Adobe® AIR™ para Adobe® Flash® CS3 Professional ou Adobe® Flash® CS4 Professional, o arquivo de descrição do aplicativo é gerado automaticamente quando você cria um projeto do AIR. Você pode acessar um painel para alterar as configurações do descritor do aplicativo do menu Comandos > AIR - Configurações do instalador e do aplicativo. Você também pode editar o arquivo do descritor do aplicativo manualmente. A estrutura do arquivo do descritor do aplicativo O arquivo do descritor do aplicativo contém propriedades que afetam todo o aplicativo, como seu nome, versão, direitos autorais e assim por diante. Qualquer nome de arquivo pode ser usado pelo arquivo do descritor do aplicativo. Quando você cria um arquivo do AIR usando as configurações padrão do Flash CS3 ou Flash CS4, o arquivo de descrição do aplicativo é renomeado para application.xml e colocado dentro de um diretório especial no pacote do AIR. Veja um exemplo do arquivo do descritor do aplicativo: <?xml version="1.0" encoding="utf-8" ?> <application xmlns="http://ns.adobe.com/air/application/1.5"> <id>com.example.HelloWorld</id> <version>2.0</version> <filename>Hello World</filename> <name>Example Co. AIR Hello World</name> <description> <text xml:lang="en">This is a example.</text> <text xml:lang="fr">C'est un exemple.</text> <text xml:lang="es">Esto es un ejemplo.</text> </description> <copyright>Copyright (c) 2006 Example Co.</copyright> <initialWindow> <title>Hello World</title> <content> HelloWorld-debug.swf </content> <systemChrome>none</systemChrome> <transparent>true</transparent> <visible>true</visible> <minimizable>true</minimizable> <maximizable>false</maximizable> <resizable>false</resizable> <width>640</width> <height>480</height> <minSize>320 240</minSize> <maxSize>1280 960</maxSize> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 45 Configuração de propriedades do aplicativo do AIR </initialWindow> <installFolder>Example Co/Hello World</installFolder> <programMenuFolder>Example Co</programMenuFolder> <icon> <image16x16>icons/smallIcon.png</image16x16> <image32x32>icons/mediumIcon.png</image32x32> <image48x48>icons/bigIcon.png</image48x48> <image128x128>icons/biggestIcon.png</image128x128> </icon> <customUpdateUI>true</customUpdateUI> <allowBrowserInvocation>false</allowBrowserInvocation> <fileTypes> <fileType> <name>adobe.VideoFile</name> <extension>avf</extension> <description>Adobe Video File</description> <contentType>application/vnd.adobe.video-file</contentType> <icon> <image16x16>icons/avfIcon_16.png</image16x16> <image32x32>icons/avfIcon_32.png</image32x32> <image48x48>icons/avfIcon_48.png</image48x48> <image128x128>icons/avfIcon_128.png</image128x128> </icon> </fileType> </fileTypes> </application> Definição de propriedades no arquivo do descritor do aplicativo Use os elementos e atributos XML de descrição do aplicativo para definir os seguintes tipos de propriedades do seu aplicativo do AIR: • Versão de tempo de execução exigida pelo AIR • Identidade do aplicativo • Pastas de instalação e de menu de programas • Conteúdo inicial e propriedades de janela • Arquivos de ícone do aplicativo • Se o aplicativo oferece uma interface do usuário atualizada e personalizada. • Se o aplicativo pode ser chamado pelo conteúdo SWF em execução no navegador do usuário. • Associações de tipo de arquivo Especificação da versão exigida pelo AIR Os atributos do elemento raiz de um arquivo de descrição do aplicativo, application, especifica a versão de tempo de execução exigida pelo AIR: <application xmlns="http://ns.adobe.com/air/application/1.5"> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 46 Configuração de propriedades do aplicativo do AIR xmlns O namespace do AIR, que você deve definir como o namespace XML padrão. O namespace é alterado com cada versão principal do AIR (mas não com patches secundários). O último segmento do espaço para nomes, como “1.5” indica a versão do tempo de execução exigida pelo aplicativo. Assegure-se de definir o espaço para nomes como AIR 1.5 ("http://ns.adobe.com/air/application/1.5"), caso seu aplicativo use qualquer recurso novo do AIR 1.5. Nos aplicativos baseados em SWF, a versão do tempo de execução do AIR especificada na descrição do aplicativo determina a versão máxima do SWF que pode ser carregada como o conteúdo inicial do aplicativo. Aplicativos que especificam AIR 1.0 ou AIR 1.1 só podem usar arquivos SWF9 (Flash Player 9) como conteúdo inicial, mesmo quando executados usando o tempo de execução do AIR 1.5. Aplicativos que especificam AIR 1.5 podem usar arquivos SWF9 ou SWF10 (Flash Player 10) como conteúdo inicial. A versão do SWF determina que versão do AIR e APIs do Flash Player estão disponíveis. Se um arquivo SWF9 for usado como conteúdo inicial de um aplicativo do AIR 1.5, esse aplicativo só terá acesso ao AIR 1.1 e às APIs do Flash Player 9. Além disso, alterações de comportamento feitas em APIs existentes no AIR 1.5 ou no Flash Player 10 não serão eficazes. (Alterações importantes relacionadas à segurança, feitas em APIs, são uma exceção a esse princípio e podem ser aplicadas de forma retroativa em patches atuais ou futuros do tempo de execução). Em aplicativos baseados em HTML, a versão do tempo de execução especificada na descrição do aplicativo determina sozinha que versão do AIR e de APIs do Flash Player estão disponíveis para o aplicativo. Os comportamentos de HTML, CSS e JavaScript são sempre determinados pela versão do Webkit usada no tempo de execução do AIR instalado, não pela descrição do aplicativo. Quando um aplicativo do AIR carrega conteúdo SWF, a versão do AIR e das APIs do Flash Player disponíveis para esse conteúdo depende de como o conteúdo é carregado. A tabela a seguir mostra como a versão da API é determinada com base no método de carregamento: Como o conteúdo é carregado Como a versão da API é determinada Conteúdo inicial, aplicativo baseado em SWF Versão SWF do arquivo carregado Conteúdo inicial, aplicativo baseado em HTML Espaço para nomes da descrição do aplicativo SWF carregado pelo conteúdo SWF Versão do conteúdo carregado Biblioteca SWF carregada pelo conteúdo HTML usando a tag <script> Espaço para nomes da descrição do aplicativo SWF carregado pelo conteúdo HTML usando o AIR ou as APIs do Flash Player (como flash.display.Loader) Espaço para nomes da descrição do aplicativo SWF carregado pelo conteúdo HTML usando as tags <object> ou <embed> (ou as APIs de JavaScript equivalentes) Versão SWF do arquivo carregado Ao carregar um arquivo SWF de uma versão diferente do conteúdo carregado, você pode se deparar com dois problemas: • Carregamento do conteúdo do SWF10 pelo SWF9 (ou anterior) — Referências ao AIR 1.5 e a APIs do Flash Player 10 no conteúdo carregado não serão resolvidas • Carregamento de conteúdo do SWF9 (ou anterior) pelo SWF10 — APIs alteradas no AIR 1.5 e Flash Player 10 podem se comportar de forma inesperada pelo conteúdo carregado. minimumPatchLevel Opcional. Use o atributo minimumPatchLevel para especificar o nível de patch mínimo do Adobe AIR exigido pelo aplicativo. Os aplicativos do AIR normalmente especificam que versão do AIR eles exigem, definindo simplesmente o namespace no arquivo do descritor do aplicativo. O espaço para nomes é alterado para cada versão principal do AIR (como 1.0 ou 1.5). O espaço para nomes não é alterado para versões de patch. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 47 Configuração de propriedades do aplicativo do AIR As versões de patch contêm apenas um conjunto limitado de correções e nenhuma alteração de API. Normalmente, os aplicativos não especificam que versão de patch exigem. No entanto, uma correção em uma versão de patch pode corrigir um problema em um aplicativo. Nesta situação, um aplicativo pode especificar um valor para o atributo minimumPatchLevel para garantir que o patch seja aplicado antes que o aplicativo seja instalado. O instalador do aplicativo do AIR solicita que o usuário baixe e instale a versão exigida ou patch, se necessário. O exemplo a seguir mostra um elemento de aplicativo que especifica um valor para o atributo minimumPatchLevel: <application xmlns="http://ns.adobe.com/air/application/1.1" minimumPatchLevel="5331"> Definição de identidade do aplicativo Os seguintes elementos definem ID do aplicativo, versão, nome, nome do arquivo, descrição e informações de copyright: <id>com.example.samples.TestApp</id> <version>2.0</version> <filename>TestApp</filename> <name> <text xml:lang="en">Hello AIR</text> <text xml:lang="fr">Bonjour AIR</text> <text xml:lang="es">Hola AIR</text> </name> <description>An MP3 player.</description> <copyright>Copyright (c) 2008 YourCompany, Inc.</copyright> id Uma seqüência de caracteres de identificador única ao aplicativo, conhecida como a ID do aplicativo. O valor de atributo é restrito aos seguintes caracteres: • 0–9 • a–z • A–Z • . (ponto) • - (hífen) O valor deve conter de 1 a 212 caracteres. Esse elemento é necessário. A seqüência de caracteres id normalmente usa uma hierarquia separada por ponto, em alinhamento com um endereço de domínio DNS revertido, um pacote Java™ ou nome de classe ou um identificador de tipo universal X do Mac OS®. A forma parecida com DNS não é aplicada e o AIR não cria nenhuma associação entre o nome e os domínios de DNS reais. version Especifica as informações de versão para o aplicativo. (Não tem relação com a versão do tempo de execução). A seqüência de caracteres da versão é um designador definido pelo aplicativo. O AIR não interpreta de maneira nenhuma a string de versão. Portanto, não se supõe que a versão “3.0” é mais atual que a versão “2.0.” Exemplos: "1.0", "0.4", "0.5", "4.9", "1.3.4a". Esse elemento é necessário. filename A seqüência de caracteres a usar como um filename do aplicativo (sem extensão) quando o aplicativo é instalado. O arquivo do aplicativo inicia o aplicativo do AIR no tempo de execução. Se nenhum valor name for fornecido, filename também será usado como o nome da pasta de instalação. Esse elemento é necessário. A propriedade filename pode conter qualquer caractere Unicode (UTF-8), exceto o seguinte, que tem o uso proibido como filenames em vários sistemas de arquivos: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 48 Configuração de propriedades do aplicativo do AIR Caractere Código hexadecimal vários 0x00 – x1F * x2A " x22 : x3A > x3C < x3E ? x3F \ x5C | x7C O valor filename não pode terminar em um ponto. name (Opcional, mas recomendado) O título exibido pelo instalador do aplicativo do AIR. Se você especificar um único nó de texto (em vez de vários elementos text), o instalador do aplicativo do AIR usa esse nome, independentemente do idioma do sistema: <name>Test Application</name> O esquema do descritor do aplicativo do AIR 1.0 permite apenas um simples nó de texto a ser definido para o nome (e não vários elementos text). No AIR 1.1 (ou acima), você pode especificar vários idiomas no elemento name. Por exemplo, o seguinte especifica o nome em três idiomas (inglês, francês e espanhol): <name> <text xml:lang="en">Hello AIR</text> <text xml:lang="fr">Bonjour AIR</text> <text xml:lang="es">Hola AIR</text> </name> O atributo xml:lang para cada elemento de texto especifica um código de idioma, como definido em RFC4646 (http://www.ietf.org/rfc/rfc4646.txt). O instalador do aplicativo do AIR usa o nome que mais se aproxima do idioma da interface do usuário do sistema operacional do usuário. Por exemplo, considere uma instalação na qual o elemento name do arquivo do descritor do aplicativo inclui um valor para o local en (inglês). O instalador do aplicativo do AIR usa o nome en se o sistema operacional identifica en (inglês) como o idioma da interface do usuário. Ele também usa o nome en se o idioma da interface do usuário do sistema for en-US (inglês norte-americano). No entanto, se o idioma da interface do usuário é en-US e o arquivo do descritor do aplicativo define os nomes en-US e en-GB, o instalador do aplicativo do AIR usa o valor en-US. Se o aplicativo não define nenhum nome que corresponda aos idiomas da interface do usuário do sistema, o instalador do aplicativo do AIR usa o primeiro valor name definido no arquivo do descritor do aplicativo. Se nenhum elemento name for especificado, o instalador do aplicativo do AIR exibirá filename como o nome do aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 49 Configuração de propriedades do aplicativo do AIR O elemento name define apenas o título do aplicativo usado no instalador do aplicativo do AIR. O instalador do aplicativo do AIR suporta vários idiomas: chinês tradicional, chinês simplificado, tcheco, holandês, inglês, francês, alemão, italiano, japonês, coreano, português do Brasil, russo, espanhol, sueco e turco. O instalador do aplicativo do AIR seleciona seu idioma exibido (para texto que não seja o título do aplicativo e a descrição) com base no idioma da interface do usuário do sistema. Essa seleção de idioma é independente das configurações no arquivo do descritor do aplicativo. O elemento namenão define as localidades disponíveis para o aplicativo instalado em execução. Para obter detalhes sobre o desenvolvimento de aplicativos com vários idiomas, consulte “Localização de aplicativos AIR” na página 343. description (Opcional) A descrição do aplicativo, exibida no instalador do aplicativo do AIR. Se você especificar um único nó de texto (e não vários elementos text), o instalador do aplicativo do AIR usará essa descrição, independentemente do idioma do sistema: <description>This is a sample AIR application.</description> O esquema do descritor do aplicativo do AIR 1.0 permite apenas um simples nó de texto a ser definido para o nome (e não vários elementos text). No AIR 1.1 (ou acima), você pode especificar vários idiomas no elemento description. Por exemplo, o seguinte especifica uma descrição em três idiomas (inglês, francês e espanhol): <description> <text xml:lang="en">This is a example.</text> <text xml:lang="fr">C'est un exemple.</text> <text xml:lang="es">Esto es un ejemplo.</text> </description> O atributo xml:lang para cada elemento de texto especifica um código de idioma, como definido em RFC4646 (http://www.ietf.org/rfc/rfc4646.txt). O instalador do aplicativo do AIR usa a descrição que mais se aproxima do idioma da interface do usuário do sistema operacional do usuário. Por exemplo, considere uma instalação na qual o elemento description do arquivo do descritor do aplicativo inclui um valor para o local en (inglês). O instalador do aplicativo do AIR usa o nome en se o sistema do usuário identifica en (inglês) como o idioma da interface do usuário. Ele também usa o nome en se o idioma da interface do usuário do sistema for en-US (inglês norte-americano). No entanto, se o idioma da interface do usuário do sistema é en-US e o arquivo do descritor do aplicativo define os nomes en-US e en-GB, o instalador do aplicativo do AIR usa o valor en-US. Se o aplicativo não define nenhum nome que corresponda ao idioma da interface do usuário do sistema, o instalador do aplicativo do AIR usa o primeiro valor description definido no arquivo do descritor do aplicativo. Para obter mais informações sobre o desenvolvimento de aplicativos com vários idiomas, consulte “Localização de aplicativos AIR” na página 343. copyright (Opcional) As informações de copyright para o aplicativo do AIR. No Mac OS, o texto de copyright é exibido caixa de diálogo Sobre para o aplicativo instalado. No Mac OS, as informações de copyright também são usadas no campo NSHumanReadableCopyright no arquivo Info.plist para o aplicativo. Definição das pastas de instalação e menu de programas As pastas de instalação e menu de programas são definidas com as seguintes configurações de propriedade: <installFolder>Acme</installFolder> <programMenuFolder>Acme/Applications</programMenuFolder> installFolder (Opcional) Identifica o subdiretório do diretório de instalação padrão. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 50 Configuração de propriedades do aplicativo do AIR No Windows, o subdiretório de instalação padrão é Arquivos de Programas. No Mac OS, é o diretório /Applications. No Linux, é /opt/. Por exemplo, se a propriedade installFolder é definida como "Acme" e um aplicativo é chamado de "ExampleApp", o aplicativo é instalado em C:\Arquivos de Programas\Acme\ExampleApp no Windows, em /Applications/Acme/Example.app no Mac OS e em /opt/Acme/ExampleApp no Linux. Use o caractere de barra (/) como o caractere separador de diretório se desejar especificar um subdiretório aninhado, como a seguir: <installFolder>Acme/Power Tools</installFolder> A propriedade installFolder pode conter qualquer caractere Unicode (UTF-8), exceto aqueles cujo uso é proibido como nomes de pastas em vários sistemas de arquivos (consulte a propriedade filename acima para obter a lista de exceções). A propriedade installFolder é opcional. Se você não especificar nenhuma propriedade installFolder, o aplicativo será instalado em um subdiretório do diretório de instalação padrão, com base na propriedade name. programMenuFolder (Opcional) Identifica o local no qual colocar atalhos para o aplicativo no menu Todos os Programas do sistema operacional Windows ou no menu Aplicativos do Linux. (Essa configuração é atualmente ignorada em outros sistemas operacionais.) As restrições sobre os caracteres permitidos no valor da propriedade são iguais às da propriedade installFolder. Não use um caractere de barra (/) como o último caractere desse valor. Definição das propriedades da janela inicial do aplicativo Quando um aplicativo do AIR é carregado, o tempo de execução usa os valores no elemento initialWindow para criar a janela inicial do aplicativo. O tempo de execução carrega o arquivo SWF ou HTML especificado no elemento content na janela. Veja um exemplo do elemento initialWindow: <initialWindow> <content>AIRTunes.swf</content> <title>AIR Tunes</title> <systemChrome>none</systemChrome> <transparent>true</transparent> <visible>true</visible> <minimizable>true</minimizable> <maximizable>true</maximizable> <resizable>true</resizable> <width>400</width> <height>600</height> <x>150</x> <y>150</y> <minSize>300 300</minSize> <maxSize>800 800</maxSize> </initialWindow> Os elementos filho do elemento initialWindow definem as propriedades da janela na qual o arquivo do conteúdo raiz é carregado. content O valor especificado para o elemento content é a URL para o arquivo principal de conteúdo do aplicativo. Isso pode ser um arquivo SWF ou HTML. A URL é especificada em relação à raiz da pasta de instalação do aplicativo. (Ao executar um aplicativo do AIR com o ADL, a URL é relativa à pasta que contém o arquivo do descritor do aplicativo. Você pode usar o parâmetro root-dir do ADL para especificar um diretório de raiz diferente.) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 51 Configuração de propriedades do aplicativo do AIR Nota: Como o valor do elemento content é tratado como uma URL, os caracteres no nome do arquivo de conteúdo devem ser codificados por URL de acordo com as regras definidas em RFC 1738. Caracteres de espaço, por exemplo, devem ser codificados como %20. title (Opcional) O título da janela. systemChrome (Opcional) Se você definiu esse atributo como standard, o cromo do sistema padrão fornecido pelo sistema operacional será exibido. Se você o definiu como none, nenhum cromo do sistema será exibido. A configuração do cromo do sistema não pode ser alterada em tempo de execução. transparent (Opcional) Definido como "true" se você deseja que a janela do aplicativo suporte mesclagem alfa. Uma janela com transparência pode ser desenhada mais lentamente e exigir mais memória. A configuração de transparente não pode ser alterada em tempo de execução. Importante: Você pode definir apenas transparent como true quando systemChrome for none. visible (Opcional) Definido como true se você desejar que a janela principal seja visível assim que ela for criada. O valor padrão é false. Você pode querer deixar a janela principal oculta inicialmente, para que alterações na posição da janela, no tamanho da janela e o layout de seu conteúdo não sejam exibidos. Você pode então exibir a janela chamando o método activate() da janela ou definindo a propriedade visible como true. Para obter detalhes, consulte “Trabalhar com janelas nativas” na página 59. x, y, width, height (Opcional) Os limites iniciais da janela principal do aplicativo. Se você não definir esses valores, o tamanho da janela será determinado pelas configurações no arquivo SWF raiz ou, no caso de HTML, pelo sistema operacional. minSize, maxSize (Opcional) Os tamanhos mínimo e máximo da janela. Se você não definir esses valores, eles serão determinados pelo sistema operacional. minimizable, maximizable, resizable (Opcional) Especifica se a janela pode ser minimizada, maximizada e redimensionada. Por padrão, essas configuração são true. Nota: Em sistemas operacionais como o Mac OS X, em que maximizar janelas é uma operação de redimensionamento, tanto maximizable quanto resizable devem ser definidos como false para impedir que a janela seja ampliada ou redimensionada. Especificar arquivos de ícone A propriedade icon especifica um ou mais arquivos de ícone a serem usados pelo aplicativo. Incluir um ícone é opcional. Se você não especificar uma propriedade icon, o sistema operacional exibirá um ícone padrão. O caminho especificado é relativo ao diretório raiz do aplicativo. Os arquivos de ícone devem estar no formato PNG. Você pode especificar todos os tamanhos de ícones a seguir: <icon> <image16x16>icons/smallIcon.png</image16x16> <image32x32>icons/mediumIcon.png</image32x32> <image48x48>icons/bigIcon.png</image48x48> <image128x128>icons/biggestIcon.png</image128x128> </icon> Se um elemento para um determinado tamanho estiver presente, a imagem no arquivo deverá ser exatamente do tamanho especificado. Se todos os tamanhos não forem fornecidos, o tamanho mais próximo será dimensionado para se ajustar para um determinado uso do ícone pelo sistema operacional. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 52 Configuração de propriedades do aplicativo do AIR Nota: Os ícones especificados não são automaticamente adicionados ao pacote do AIR. Os arquivos de ícone devem ser incluídos em seus locais corretos relativos quando o aplicativo for empacotado. Para melhores resultados, forneça uma imagem para cada um dos tamanhos disponíveis. Além disso, verifique se os ícones estão apresentáveis nos modos de cores de 16 e 32 bits. Fornecer uma interface de usuário personalizada para atualizações de aplicativos O AIR instala e atualiza aplicativos usando as caixas de diálogo de instalação padrão. No entanto, você pode fornecer sua própria interface de usuário para atualizar um aplicativo. Para indicar que seu aplicativo deve manipular o processo de atualização sozinho, defina o elemento customUpdateUI como true: <customUpdateUI>true</customUpdateUI> Quando a versão instalada do seu aplicativo tiver o elemento customUpdateUI definido como true e o usuário clicar duas vezes no arquivo do AIR para uma nova versão ou instalar uma atualização do aplicativo usando o recurso de instalação direta, o tempo de execução abre a versão instalada do aplicativo, em vez do instalador do aplicativo do AIR padrão. A lógica do seu aplicativo pode então determinar como proceder com a operação de atualização. (As IDs do aplicativo e do editor no arquivo do AIR devem corresponder àquelas do aplicativo instalado para uma atualização poder continuar.) Nota: O mecanismo customUpdateUI apenas começa a funcionar quando o aplicativo já está instalado e o usuário clica duas vezes no arquivo de instalação do AIR que contém uma atualização ou instala uma atualização do aplicativo usando o recurso de instalação direta. Você pode baixar e iniciar uma atualização pela lógica do seu aplicativo, exibindo sua interface de usuário personalizada conforme necessário, seja customUpdateUItrue ou não. Para obter mais informações, consulte “Atualização de aplicativos do AIR” na página 328. Permitir invocação do navegador do aplicativo Se você especificar a seguinte definição, o aplicativo do AIR instalado poderá ser iniciado pelo recurso de invocação do navegador (o usuário deve clicar em um link de uma página no navegador da Web): <allowBrowserInvocation>true</allowBrowserInvocation> O valor padrão é false. Se você definiu esse valor como true, certifique-se de considerar implicações de segurança, descritas em “Invocação do navegador” na página 294. Para obter mais informações, consulte “Instalação e execução de aplicativos do AIR de uma página da Web” na página 313. Declaração de associações de tipo de arquivo O elemento fileTypes permite que você declare os tipos de arquivos com os quais um aplicativo do AIR pode ser associado. Quando um aplicativo do AIR é instalado, qualquer tipo de arquivo declarado é registrado com o sistema operacional e, se esses tipos de arquivos ainda não estão associados a outro aplicativo, são associados ao aplicativo do AIR. Para substituir uma associação existente entre um tipo de arquivo e outro aplicativo, use o método NativeApplication.setAsDefaultApplication() em tempo de execução (preferencialmente com a permissão do usuário). Nota: Os métodos runtime podem apenas gerenciar associações para os tipos de arquivos declarados no descritor do aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 53 Configuração de propriedades do aplicativo do AIR <fileTypes> <fileType> <name>adobe.VideoFile</name> <extension>avf</extension> <description>Adobe Video File</description> <contentType>application/vnd.adobe.video-file</contentType> <icon> <image16x16>icons/AIRApp_16.png</image16x16> <image32x32>icons/AIRApp_32.png</image32x32> <image48x48>icons/AIRApp_48.png</image48x48> <image128x128>icons/AIRApp_128.png</image128x128> </icon> </fileType> </fileTypes> O elemento fileTypes é opcional. Ele pode conter qualquer número de elementos fileType. Os elementos name e extension são necessários para cada declaração fileType que você inclui. O mesmo nome pode ser usado para várias extensões. A extensão identifica unicamente o tipo de arquivo. (Observe que a extensão é especificada sem o ponto anterior.) O elemento description é opcional e é exibido ao usuário pela interface de usuário do sistema operacional. O contentType é exigido no AIR 1.5 (ele era opcional no AIR 1.0 e 1.1). A propriedade ajuda o sistema operacional a localizar o melhor aplicativo para abrir um arquivo em algumas circunstâncias. O valor deve ser o tipo MIME do conteúdo do arquivo. Observe que o valor será ignorado no Linux se o tipo de arquivo já estiver registrado e tiver um tipo MIME atribuído. Os ícones podem ser especificados para a extensão do arquivo, usando o mesmo formato do elemento do ícone do aplicativo. Os arquivos do ícone deve também ser incluídos no arquivo de instalação do AIR (eles não são empacotados automaticamente). Quando um tipo de arquivo é associado a um aplicativo do AIR, o aplicativo será invocado sempre que um usuário abre um arquivo desse tipo. Se o aplicativo já estiver em execução, o AIR irá despachar o objeto InvokeEvent para a instância em execução. Caso contrário, o AIR lançará o aplicativo primeiro. Nos dois casos, o caminho para o arquivo pode ser recuperado do objeto InvokeEvent despachado pelo objeto NativeApplication. Você pode usar esse caminho para abrir o arquivo. Para obter mais informações, consulte “Gerenciamento de associações de arquivos” na página 299 e “Captura de argumentos de linha de comando” na página 292. 54 Capítulo 9: Adobe AIR - funcionalidade específica Esse tópico fornece uma visão geral da funcionalidade do Adobe® AIR™ que não está disponível para conteúdo do SWF executado no Adobe® Flash® Player. Classes específicas do AIR As classes de tempos de execução a seguir são específicas do Adobe AIR. Elas não estão disponíveis para conteúdo do SWF em execução no navegador: Classe Pacote ApplicationUpdater air.update ApplicationUpdaterUI air.update BrowserInvokeEvent flash.events Clipboard flash.desktop ClipboardFormats flash.desktop ClipboardTransferMode flash.desktop CompressionAlgorithm flash.utils DockIcon flash.desktop DownloadErrorEvent air.update.events DRMAuthenticateEvent flash.events DRMErrorEvent flash.events DRMStatusEvent flash.events EncryptedLocalStore flash.data File flash.filesystem FileListEvent flash.events FileMode flash.filesystem FileStream flash.filesystem FocusDirection flash.display HTMLHistoryItem flash.html HTMLHost flash.html HTMLLoader flash.html HTMLPDFCapability flash.html HTMLUncaughtScriptExceptionEvent flash.events DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 55 Adobe AIR - funcionalidade específica Classe Pacote HTMLWindowCreateOptions flash.html Icon flash.desktop InteractiveIcon flash.desktop InvokeEvent flash.events NativeApplication flash.desktop NativeDragActions flash.desktop NativeDragEvent flash.events NativeDragManager flash.desktop NativeDragOptions flash.desktop NativeMenu flash.display NativeMenuItem flash.display NativeWindow flash.display NativeWindowBoundsEvent flash.events NativeWindowDisplayState flash.display NativeWindowDisplayStateEvent flash.events NativeWindowInitOptions flash.display NativeWindowResize flash.display NativeWindowSystemChrome flash.display NativeWindowType flash.display NotificationType flash.desktop OutputProgressEvent flash.events RevocationCheckSettings flash.security Screen flash.display ScreenMouseEvent flash.events SignatureStatus flash.security SignerTrustSettings flash.security SQLCollationType flash.data SQLColumnNameStyle flash.data SQLColumnSchema flash.data SQLConnection flash.data SQLError flash.errors SQLErrorEvent flash.events SQLErrorOperation flash.errors SQLEvent flash.events DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 56 Adobe AIR - funcionalidade específica Classe Pacote SQLIndexSchema flash.data SQLResult flash.data SQLSchema flash.data SQLSchemaResult flash.data SQLStatement flash.data SQLTableSchema flash.data SQLTransactionLockType flash.data SQLTriggerSchema flash.data SQLUpdateEvent flash.events SQLViewSchema flash.data StatusFileUpdateErrorEvent air.update.events StatusFileUpdateEvent air.update.events StatusUpdateErrorEvent air.update.events StatusUpdateEvent air.update.events SystemTrayIcon flash.desktop UpdateEvent air.update.events Updater flash.desktop URLRequestDefaults flash.net XMLSignatureValidator flash.utils Além disso, o pacote flash.security inclui a interface do IURIDereferencer, específica do AIR. Classes de tempo de execução com funcionalidade específica do AIR As classes a seguir estão disponíveis para conteúdo do SWF em execução no navegador, mas o AIR fornece métodos ou propriedades adicionais: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 57 Adobe AIR - funcionalidade específica Classe Propriedade ou método Capabilities idiomas Event DISPLAYING EXITING HTML_BOUNDS_CHANGE HTML_DOM_INITIALIZE HTML_RENDER LOCATION_CHANGE NETWORK_CHANGE USER_IDLE USER_PRESENT FileReference uploadUnencoded() HTTPStatusEvent HTTP_RESPONSE_STATUS responseURL responseHeaders KeyboardEvent commandKey controlKey LoaderContext allowLoadBytesCodeExecution LoaderInfo parentSandboxBridge childSandboxBridge NetStream resetDRMVouchers() setDRMAuthenticationCredentials() URLRequest followRedirects manageCookies shouldAuthenticate shouldCacheResponse userAgent userCache setLoginCredentials() URLStream httpResponseStatus event Stage nativeWindow Security APPLICATION A maioria dessas novas propriedades e métodos estão disponíveis apenas para conteúdo na caixa de proteção de segurança de aplicativos do AIR. No entanto, os novos membros nas classes URLRequest também estão disponíveis para conteúdo em execução em outras caixas de proteção. Os métodos ByteArray.compress() e ByteArray.uncompress() incluem, cada um, um novo parâmetro algorithm, permitindo que você escolha entre a compactação deflate e zlib. Esse parâmetro só está disponível para conteúdo em execução no AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 58 Adobe AIR - funcionalidade específica Classes de estrutura de monitoramento de serviço O pacote air.net contém classes para detecção de rede. Este pacote só está disponível para conteúdo em execução no Adobe AIR. Ele está incluído no arquivo ServiceMonitor.swc. O pacote inclui as seguintes classes: • ServiceMonitor • SocketMonitor • URLMonitor 59 Capítulo 10: Trabalhar com janelas nativas Use as classes fornecidas pela API de janela nativa do Adobe® AIR® para criar e gerenciar janelas da área de trabalho. Mais informações on-line sobre janelas nativas Você encontra mais informações sobre a API de janela nativa e como trabalhar com janelas nativas nestas fontes: Início rápido (Adobe AIR Developer Connection) • Interação com uma janela • Personalização da aparência de uma janela nativa • Criação de janelas no estilo pop-up • Controle da ordem de exibição das janelas • Criação de janelas não retangulares redimensionáveis Referência de linguagem • NativeWindow • NativeWindowInitOptions Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (procure 'Janelas do AIR') Noções básicas sobre janelas do AIR O AIR oferece uma API de janelas fácil de usar e compatível com várias plataformas, que permite criar janelas de sistema operacional nativas usando técnicas de programação em Flash®, Flex™ e HTML. Com o AIR, você tem grande liberdade para desenvolver a aparência do seu aplicativo. As janelas que você cria parecem um aplicativo padrão de área de trabalho, correspondendo ao estilo Apple quando em execução no Mac, em conformidade com convenções Microsoft quando executadas no Windows e em harmonia com o gerenciador de janelas do Linux, tudo sem incluir um código específico de linha de plataforma. Se preferir, você pode usar o cromo extensível e que pode ter a capa trocada, fornecido pela estrutura do Flex, para estabelecer o seu próprio estilo, independentemente do local onde o aplicativo é executado. Você pode até mesmo desenhar seus próprios cromos de janelas usando arte final vetorial e de bitmap com suporte completo para transparência e mesclagem alfa na área de trabalho. Cansado de janelas retangulares? Desenhe uma redonda. Janelas no AIR O AIR suporta três APIs diferentes para se trabalhar com janelas: • A classe NativeWindow orientada para ActionScript fornece o nível mais baixo de API de janela. Use o NativeWindows em aplicativos de autoria Flash CS e ActionScript. Considere estender a classe NativeWindow para especializar as janelas usadas em seu aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 60 Trabalhar com janelas nativas • As classes mx:WindowedApplication e mx:Window da estrutura do Flex fornecem um "invólucro" para a classe NativeWindow. O componente WindowedApplication substitui o componente Application quando você cria um aplicativo do AIR com Flex e deve ser sempre usado como janela inicial no aplicativo Flex. • No ambiente HTML, você pode usar a classe JavaScript Window, assim como faria em um aplicativo da Web baseado em navegador. As chamadas para os métodos JavaScript Window são encaminhadas para o objeto janela nativo subjacente. Janelas ActionScript Quando criar janelas com a classe NativeWindow, use a lista de exibição no palco do Flash Player diretamente. Para adicionar um objeto visual a uma NativeWindow, adicione o objeto à lista de exibição do palco da janela ou a outro contêiner do objeto de exibição no palco. Janelas da estrutura do Flex A estrutura do Flex define seus próprios componentes de janela que abrangem a API NativeWindow. Esses componentes (mx:WindowedApplication e mx:Window) não podem ser usados fora da estrutura e, portanto, não podem ser usados em aplicativos do AIR desenvolvidos com Flash CS. Janelas HTML Quando cria janelas HTML, você usa HTML, CSS e JavaScript para exibir o conteúdo. Para adicionar um objeto visual a uma janela HTML, você adiciona esse conteúdo ao HTML DOM. As janelas HTML são uma categoria especial de NativeWindow. O host do AIR define uma propriedade nativeWindow em janelas HTML que dá acesso à ocorrência subjacente de NativeWindow. Você pode usar essa propriedade para acessar as propriedades, os métodos e os eventos de NativeWindow descritos aqui. Nota: O objeto JavaScript Window também tem métodos para gerar scripts da janela que o contém, como moveTo() e close(). Se houver métodos de sobreposição disponíveis, você poderá usar o método mais conveniente. A janela inicial do aplicativo. A primeira janela do seu aplicativo é criada automaticamente para você pelo AIR. O AIR define as propriedades e o conteúdo da janela usando os parâmetros especificados no elemento initialWindow do arquivo de descrição do aplicativo. Se o conteúdo raiz é um arquivo SWF, o AIR cria uma ocorrência de NativeWindow, carrega o arquivo SWF e o adiciona ao palco da janela. Se o conteúdo raiz é um arquivo HTML, o AIR cria uma janela HTML e carrega o código HTML. Para obter mais informações sobre as propriedades de janela especificadas no descritor do aplicativo, consulte “A estrutura do arquivo do descritor do aplicativo” na página 44. Classes de janela nativa A API de janela nativa contém as seguintes classes: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 61 Trabalhar com janelas nativas Pacote Classes flash.display • NativeWindow • NativeWindowInitOptions • NativeWindowDisplayState • NativeWindowResize • NativeWindowSystemChrome • NativeWindowType Constantes de string de janela são definidas nas seguintes classes: flash.events • NativeWindowDisplayState • NativeWindowResize • NativeWindowSystemChrome • NativeWindowType • NativeWindowBoundsEvent • NativeWindowDisplayStateEvent Fluxo de eventos de janelas nativas As janelas nativas despacham eventos para notificar os componentes interessados de que uma alteração importante está prestes a ocorrer ou já ocorreu. Muitos eventos relacionados a janelas são despachados em pares. O primeiro evento avisa que uma alteração está prestes a ocorrer. O segundo comunica que a alteração foi feita. É possível cancelar um evento de aviso, mas não um evento de notificação. Esta seqüência ilustra o fluxo de eventos que ocorre quando um usuário clica no botão Maximizar de uma janela: 1 O objeto NativeWindow despacha um evento displayStateChanging. 2 Se nenhum ouvinte registrado cancelar o evento, a janela será maximizada. 3 O objeto NativeWindow despacha um evento displayStateChange. Além disso, o objeto NativeWindow despacha eventos de alterações relacionadas feitas no tamanho e na posição de uma janela. A janela não despacha eventos de aviso referentes a essas alterações relacionadas. Os eventos relacionados são: a Um evento move é despachado se o canto superior esquerdo da janela foi movido por causa da operação de maximização. b Um evento resize é despachado se o tamanho da janela mudou devido à operação de maximização. Um objeto NativeWindow despacha uma seqüência semelhante de eventos quando maximiza, restaura, fecha, movimenta e redimensiona uma janela. Os eventos de aviso são despachados somente quando uma alteração é iniciada através do cromo da janela ou de outro mecanismo controlado pelo sistema operacional. Quando você chama um método de janela para alterar o tamanho, a posição ou o estado de exibição de uma janela, a janela só despacha um evento para comunicar a alteração. Se desejar, você pode despachar um evento de aviso usando o método de janela dispatchEvent() e, depois, verificar se o seu evento de aviso foi cancelado antes de prosseguir com a alteração. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 62 Trabalhar com janelas nativas Para obter informações detalhadas sobre as classes, os métodos, as propriedades e os eventos da API de janela, consulte a Referência dos componentes e da linguagem do de linguagem do ActionScript 3.0 (http://www.adobe.com/go/learn_flash_aslr_br). Para obter informações gerais sobre como usar a lista de exibição do Flash, consulte a seção “Programação da exibição” na referência Programação do Adobe ActionScript 3.0 (http://www.adobe.com/go/learn_fl_cs4_programmingAS3_en). Propriedades que controlam o estilo e o comportamento de janelas nativas As seguintes propriedades controlam a aparência e o comportamento básicos de uma janela: • type • systemChrome • transparent Quando cria uma janela, você define essas propriedades no objeto NativeWindowInitOptions passado para o construtor da janela. O AIR lê as propriedades da janela inicial do aplicativo no descritor do aplicativo. (Com exceção da propriedade type, que não pode ser definida no descritor do aplicativo e é sempre definida como normal.) Não é possível alterar as propriedades após a criação da janela. Algumas configurações dessas propriedades são mutuamente incompatíveis: systemChrome não pode ser definida como standard quando transparent é true ou quando type é lightweight. Tipos de janela Os tipos de janela do AIR combinam atributos de cromo e visibilidade do sistema operacional nativo para criar três tipos funcionais de janela. Use as constantes definidas na classe NativeWindowType para fazer referência aos nomes de tipo no código. O AIR oferece os seguintes tipos de janela: Tipo Descrição Normal Uma janela típica. As janelas normais usam o cromo de estilo em tamanho máximo e são exibidas na barra de tarefas do Windows e no menu de janela do Mac OS X. Utilitário Uma paleta de ferramentas. As janelas de utilitário usam uma versão reduzida do cromo do sistema e não são exibidas na barra de tarefas do Windows nem no menu de janela do Mac OS X. Leve As janelas leves não têm cromo e não são exibidas na barra de tarefas do Windows nem no menu de janela do Mac OS X. Além disso, as janelas leves não têm o menu Sistema (Alt+espaço) no Windows. As janelas leves são adequadas para as bolhas de notificação e controles como caixas de combinação que abrem uma área de exibição de curta duração. Quando se usa o tipo leve, a propriedade systemChrome deve ser definida como none. Cromo de janela O cromo de janela é o conjunto de controles que permitem aos usuários manipular uma janela no ambiente da área de trabalho. Os elementos do cromo incluem a barra de título e seus botões, borda e alças de redimensionamento. Cromo do sistema É possível definir a propriedade systemChrome como standard ou none. Escolha o cromo do sistema standard para dar à sua janela o conjunto de controles padrão criados e estilizados pelo sistema operacional do usuário. Escolha none para fornecer o seu próprio cromo para a janela. Use as constantes definidas na classe NativeWindowSystemChrome para fazer referência às configurações de cromo do sistema no código. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 63 Trabalhar com janelas nativas O cromo do sistema é gerenciado pelo sistema. Seu aplicativo não tem acesso direto aos controles propriamente ditos, mas pode reagir a eventos despachados quando eles são usados. Quando você usa o cromo padrão para uma janela, a propriedade transparent deve ser definida como false e a propriedade type deve ser normal ou utility. Cromo personalizado Se você criar uma janela sem um cromo do sistema, deverá adicionar seus próprios controles de cromo para administrar as interações entre um usuário e a janela. Você também tem liberdade para criar janelas não retangulares transparentes. Transparência de janelas Para permitir a mesclagem alfa de uma janela com a área de trabalho ou outras janelas, defina a propriedade transparent da janela como true. A propriedade transparent deve ser definida antes de a janela ser criada e não é possível alterá-la. Uma janela transparente não tem um plano de fundo padrão. Qualquer área da janela que não contém um objeto desenhado pelo aplicativo fica invisível. Se um objeto exibido tiver uma configuração alfa de menos de 1, qualquer coisa abaixo do objeto ficará transparente, inclusive outros objetos de exibição na mesma janela, em outras janelas e na área de trabalho. O processamento de grandes áreas com mesclagem alfa pode ser lento, por isso o efeito deve ser usado com cautela. As janelas transparentes são úteis quando você deseja criar aplicativos com bordas irregulares ou que “desaparecem” ou mesmo parecem ser invisíveis. Importante: No Linux, eventos de mouse não passam por pixels totalmente transparentes. Você deve evitar criar janelas com áreas grandes totalmente transparentes, já que isso pode bloquear invisivelmente o acesso do usuário a outras janelas ou itens na área de trabalho. No Mac OS X e no Windows, eventos de mouse passam por pixels totalmente transparentes. A transparência não pode ser usada com janelas que têm um cromo do sistema. Além disso, os conteúdos SWF e PDF em HTML não são exibidos em janelas transparentes. Para obter mais informações, consulte “Considerações ao carregar conteúdo SWF ou PDF em uma página HTML” na página 259. Em alguns sistemas operacionais, pode não haver suporte para transparência devido à configuração de hardware ou software ou às opções de exibição definidas pelo usuário. Quando não há suporte para transparência, o aplicativo é composto com um plano de fundo preto. Nesses casos, qualquer área transparente do aplicativo é exibida como uma área preta opaca. A propriedade estática NativeWindow.supportsTransparency informa se a transparência de janela pode ser usada. Se o teste dessa propriedade retornar false, por exemplo, você poderá exibir uma caixa de diálogo de aviso para o usuário ou exibir uma interface de usuário de fallback retangular não transparente . Vale observar que sempre há suporte para transparência nos sistemas operacionais Mac e Windows. O suporte em sistemas operacionais Linux requer um gerenciador de composição de janela, mas mesmo quando um gerenciador de composição de janela está ativo, a transparência pode estar indisponível devido às opções de exibição do usuário ou configuração de hardware. Transparência em uma janela de aplicativo HTML Por padrão, o plano de fundo do conteúdo HTML exibido em janelas HTML e objetos HTMLLoader é opaco, mesmo quando a janela que o contém é transparente. Para desativar o plano de fundo padrão exibido com conteúdo HTML, defina a propriedade paintsDefaultBackground como false. O exemplo abaixo cria um objeto HTMLLoader e desativa o plano de fundo padrão: var html:HTMLLoader = new HTMLLoader(); html.paintsDefaultBackground = false; Este exemplo usa JavaScript para desativar o plano de fundo padrão de uma janela HTML: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 64 Trabalhar com janelas nativas window.htmlLoader.paintsDefaultBackground = false; Se um elemento do documento HTML define uma cor de plano de fundo, o plano de fundo desse elemento não fica transparente. Não há suporte para definir um valor de transparência parcial (ou opacidade). No entanto, você pode usar um elemento gráfico no formato PNG transparente para uma página ou um elemento de página a fim de obter um efeito visual semelhante. Um catálogo de janelas visuais A seguinte tabela ilustra os efeitos visuais de diferentes combinações de configurações de propriedades de janela nos sistemas operacionais Mac OS X, Windows e Linux: Configurações de janela Tipo: normal SystemChrome: standard Transparente: false Tipo: utilitário SystemChrome: standard Transparente: false Mac OS X Microsoft Windows Linux* DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 65 Trabalhar com janelas nativas Configurações de janela Mac OS X Microsoft Windows Linux* Tipo: Qualquer um SystemChrome: none Transparente: false Tipo: Qualquer um SystemChrome: none Transparente: true mxWindowedApplication ou mx:Window Tipo: Qualquer um SystemChrome: none Transparente: true Gerenciador de janela *Ubuntu with Compiz Nota: Os seguintes elementos de cromo do sistema não têm suporte no AIR: a barra de ferramentas do OS X, o ícone Proxy do Mac OS X, os ícones na barra de título do Windows e o cromo do sistema alternativo. Criação de janelas O AIR cria automaticamente a primeira janela de um aplicativo, mas você pode criar qualquer outra janela de que precise. Para criar uma janela nativa, use o método de construtor NativeWindow. Para criar uma janela HTML, use o método createRootWindow() de HTMLLoader ou, em um documento HTML, chame o método JavaScript window.open(). Especificação das propriedades de inicialização de uma janela As propriedades de inicialização de uma janela não podem ser alteradas após a criação da janela da área de trabalho. Entre as propriedades imutáveis e seus valores padrão estão os seguintes: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 66 Trabalhar com janelas nativas Propriedade Valor padrão systemChrome standard type normal transparent false maximizable true minimizable true resizable true Defina as propriedades da janela inicial criada pelo AIR no arquivo de descrição do aplicativo. A janela principal de um aplicativo do AIR sempre é do tipo normal. (É possível especificar outras propriedades de janela no arquivo de descrição, tais como visible, width e height, mas elas podem ser alteradas a qualquer momento.) Defina as propriedades de outras janelas nativas e HTML criadas pelo seu aplicativo usando a classe NativeWindowInitOptions. Quando você cria uma janela, deve passar um objeto NativeWindowInitOptions que especifique as propriedades da janela para a função de construtor NativeWindow ou o método createRootWindow() de HTMLLoader. O seguinte código cria um objeto NativeWindowInitOptions para uma janela de utilitário: var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.systemChrome = NativeWindowSystemChrome.STANDARD; options.type = NativeWindowType.UTILITY options.transparent = false; options.resizable = false; options.maximizable = false; Não é permitido definir systemChrome como standard quando transparent é true ou quando type é lightweight. Nota: Não é possível definir as propriedades de inicialização de uma janela criada com a função JavaScript window.open(). No entanto, você pode ignorar como elas são criadas implementando sua própria classe HTMLHost. Para obter mais informações, consulte “Tratamento de chamadas JavaScript de window.open()” na página 268. Criação da janela inicial do aplicativo O AIR cria a janela inicial do aplicativo com base nas propriedades especificadas no descritor do aplicativo e carrega o arquivo mencionado no elemento de conteúdo. O elemento de conteúdo deve referenciar um arquivo SWF ou um arquivo HTML. A janela inicial pode ser a janela principal do seu aplicativo ou pode simplesmente servir para iniciar uma ou mais janelas. Não é necessário torná-la visível. A ferramenta Flash Authoring automaticamente cria o arquivo SWF e adiciona a referência apropriada ao descritor do aplicativo quando você testa ou publica um projeto no AIR. A linha do tempo principal funciona como o ponto de entrada do seu aplicativo. Quando seu aplicativo é iniciado, o AIR cria uma janela e carrega o arquivo SWF do aplicativo. Para controlar a janela de área de trabalho com o ActionScript, use a propriedade nativeWindow do objeto Stage para obter uma referência ao objeto NativeWindow. Dessa maneira, você poderá definir as propriedades da janela e chamar métodos de janela. O exemplo abaixo ativa a janela principal no estado maximizado (a partir do primeiro quadro de um arquivo FLA do Flash): DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 67 Trabalhar com janelas nativas import flash.display.NativeWindow; var mainWindow:NativeWindow = this.stage.nativeWindow; mainWindow.maximize(); mainWindow.activate(); Criação de um objeto NativeWindow Para criar um NativeWindow, passe um objeto NativeWindowInitOptions para o construtor NativeWindow: var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.systemChrome = NativeWindowSystemChrome.STANDARD; options.transparent = false; var newWindow:NativeWindow = new NativeWindow(options); A janela não é exibida até você definir a propriedade visible como true ou chamar o método activate(). Uma vez criada a janela, você pode inicializar suas propriedades e carregar conteúdo nela usando as técnicas de propriedade de palco e lista de exibição do Flash. Em quase todos os casos, você deve definir a propriedade de palco scaleMode de uma nova janela nativa como noScale (use a constante StageScaleMode.NO_SCALE). Os modos de dimensionamento do Flash foram desenvolvidos para situações em que o autor do aplicativo não sabe de antemão a proporção do espaço de exibição do aplicativo. Os modos de dimensionamento permitem que o autor escolha o melhor ajuste: recorte o conteúdo, aumente ou compacte o conteúdo ou preencha-o com espaço vazio. Desde que você controle o espaço de exibição no AIR (o quadro da janela), pode dimensionar a janela conforme o conteúdo ou vice-versa, sem comprometer o resultado final. Nota: Para determinar os tamanhos máximo e mínimo de uma janela permitidos no sistema operacional atual, use as seguintes propriedades estáticas da classe NativeWindow: var maxOSSize:Point = NativeWindow.systemMaxSize; var minOSSize:Point = NativeWindow.systemMinSize; Criação de uma janela HTML Para criar uma janela HTML, você pode chamar o método JavaScript Window.open() ou o método createRootWindow() da classe HTMLLoader do AIR. O conteúdo HTML em qualquer caixa de proteção de segurança pode usar o método JavaScript Window.open() padrão. Se o conteúdo estiver sendo executado fora da caixa de proteção do aplicativo, o método open() só poderá ser chamado em resposta a interações do usuário, como cliques do mouse ou pressionamentos de tecla. Quando open() é chamado, é criada uma janela com o cromo do sistema para exibir o conteúdo na URL especificada. Por exemplo: newWindow = window.open("xmpl.html", "logWindow", "height=600, width=400, top=10, left=10"); Nota: Você pode estender a classe HTMLHost no ActionScript para personalizar a janela criada com a função JavaScript window.open(). Consulte “Sobre estender a classe HTMLHost” na página 263. O conteúdo na caixa de proteção de segurança do aplicativo tem acesso ao método de criação de janelas mais eficiente, HTMLLoader.createRootWindow(). Com ele, você pode especificar todas as opções de criação de uma nova janela. Por exemplo, o seguinte código JavaScript cria uma janela do tipo leve sem cromo do sistema e com tamanho de 300x400 pixels: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 68 Trabalhar com janelas nativas var options = new air.NativeWindowInitOptions(); options.systemChrome = "none"; options.type = "lightweight"; var windowBounds = new air.Rectangle(200,250,300,400); newHTMLLoader = air.HTMLLoader.createRootWindow(true, options, true, windowBounds); newHTMLLoader.load(new air.URLRequest("xmpl.html")); Nota: Se o conteúdo carregado por uma nova janela estiver fora da caixa de proteção de segurança do aplicativo, o objeto Window não terá as propriedades do AIR: runtime, nativeWindow ou htmlLoader. As janelas criadas com o método createRootWindow() permanecem independentes da janela de abertura. As propriedades parent e opener do objeto JavaScript Window são null. A janela de abertura pode acessar o objeto Window da nova janela usando a referência a HTMLLoader retornada pela função createRootWindow(). No contexto do exemplo anterior, a instrução newHTMLLoader.window faria referência ao objeto JavaScript Window da janela criada. Nota: A função createRootWindow() pode ser chamada no JavaScript e no ActionScript. Adicionar conteúdo a uma janela O tipo de uma janela do AIR determina a maneira como você adiciona conteúdo a ela. É possível criar um clipe de filme e usar a linha do tempo para controlar o estado do aplicativo. Com HTML, você define o conteúdo básico da janela declarativamente. É possível incorporar recursos no arquivo SWF do aplicativo ou carregá-los a partir de arquivos de aplicativo separados. O conteúdo Flash e HTML pode ser criado rapidamente e adicionado a uma janela de forma dinâmica. Quando você carrega conteúdo SWF, ou HTML com JavaScript, deve levar em consideração o modelo de segurança do AIR. Qualquer conteúdo existente na caixa de proteção de segurança do aplicativo, ou seja, conteúdo instalado com seu aplicativo e carregável com o esquema de URL app:, tem privilégios totais para acessar todas as APIs do AIR. Qualquer conteúdo carregado de fora dessa caixa de proteção não pode acessar as APIs do AIR. O conteúdo JavaScript fora da caixa de proteção do aplicativo não pode usar as propriedades runtime, nativeWindow ou htmlLoader do objeto JavaScript Window. Para permitir código entre scripts seguro, você pode usar uma ponte de caixa de proteção para disponibilizar uma interface limitada entre conteúdo de aplicativo e conteúdo que não é de aplicativo. No conteúdo HTML, também é possível mapear páginas do seu aplicativo para uma caixa de proteção que não seja de aplicativo, de maneira que essa página possa cruzar scripts de conteúdo externo. Consulte “Segurança do AIR” na página 23. Carregamento de arquivo ou imagem SWF Você pode carregar arquivos ou imagens SWF do Flash na lista de exibição de uma janela nativa usando a classe flash.display.Loader: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 69 Trabalhar com janelas nativas package { import import import import flash.display.Sprite; flash.events.Event; flash.net.URLRequest; flash.display.Loader; public class LoadedSWF extends Sprite { public function LoadedSWF(){ var loader:Loader = new Loader(); loader.load(new URLRequest("visual.swf")); loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadFlash); } private function loadFlash(event:Event):void{ addChild(event.target.loader); } } } É possível carregar um arquivo SWF que contém código de biblioteca para uso em um aplicativo baseado em HTML. A maneira mais simples de carregar um arquivo SWF em uma janela HTML é usar a tag script, mas você também pode usar a API Loader diretamente. Nota: Arquivos SWF mais antigos criados com o ActionScript 1 ou 2 compartilham estados globais, como definições de classe, singletons e variáveis globais, se carregados na mesma janela. Se tal arquivo SWF depender de estados globais intocados para funcionar corretamente, não será possível carregá-lo mais de uma vez na mesma janela nem carregá-lo na mesma janela como outro arquivo SWF usando variáveis e definições de classe de sobreposição. Este conteúdo pode ser carregado em janelas separadas. Carregamento de conteúdo HTML em um objeto NativeWindow Para carregar conteúdo HTML em um NativeWindow, você pode adicionar um objeto HTMLLoader ao palco da janela e carregar o conteúdo HTML no HTMLLoader ou criar uma janela que já contenha um objeto HTMLLoader usando o método HTMLLoader.createRootWindow(). O seguinte exemplo mostra conteúdo HTML em uma área de exibição de 300 por 500 pixels no palco de uma janela nativa: //newWindow is a NativeWindow instance var htmlView:HTMLLoader = new HTMLLoader(); html.width = 300; html.height = 500; //set the stage so display objects are added to the top-left and not scaled newWindow.stage.align = "TL"; newWindow.stage.scaleMode = "noScale"; newWindow.stage.addChild( htmlView ); //urlString is the URL of the HTML page to load htmlView.load( new URLRequest(urlString) ); Nota: O conteúdo SWF ou PDF de um arquivo em HTML não é exibido se a janela utiliza transparência (ou seja, se a propriedade transparent da janela for true) ou se o controle HTMLLoader estiver dimensionado. Adicionar conteúdo SWF como sobreposição em uma janela HTML Como as janelas HTML são contidas em uma ocorrência de NativeWindow, é possível adicionar objetos de exibição do Flash tanto acima quanto abaixo da camada HTML na lista de exibição. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 70 Trabalhar com janelas nativas Para adicionar um objeto de exibição acima da camada HTML, use o método addChild() da propriedade window.nativeWindow.stage. O método addChild() adiciona conteúdo em camada acima de qualquer conteúdo existente na janela. Para adicionar um objeto de exibição abaixo da camada HTML, use o método addChildAt() da propriedade window.nativeWindow.stage, passando um valor de zero para o parâmetro index. Colocar um objeto no índice zero movimenta o conteúdo existente, inclusive a exibição HTML, uma camada acima e insere o novo conteúdo na parte inferior. Para que o conteúdo disposto abaixo da página HTML fique visível, defina a propriedade paintsDefaultBackground do objeto HTMLlLoader como false. Além disso, quaisquer elementos da página que têm uma cor de plano de fundo definida não ficarão transparentes. Por exemplo, se você definir uma cor de plano de fundo para o elemento body da página, nenhuma parte dela ficará transparente. O exemplo a seguir ilustra como adicionar objetos de exibição do Flash na forma de sobreposições e bases a uma página HTML. O exemplo cria dois objetos de forma simples, adiciona um abaixo do conteúdo HTML e um acima. O exemplo também atualiza a posição da forma com base no evento enterFrame. <html> <head> <title>Bouncers</title> <script src="AIRAliases.js" type="text/javascript"></script> <script language="JavaScript" type="text/javascript"> air.Shape = window.runtime.flash.display.Shape; function Bouncer(radius, color){ this.radius = radius; this.color = color; //velocity this.vX = -1.3; this.vY = -1; //Create a Shape object and draw a circle with its graphics property this.shape = new air.Shape(); this.shape.graphics.lineStyle(1,0); this.shape.graphics.beginFill(this.color,.9); this.shape.graphics.drawCircle(0,0,this.radius); this.shape.graphics.endFill(); //Set the starting position this.shape.x = 100; this.shape.y = 100; //Moves the sprite by adding (vX,vY) to the current position this.update = function(){ this.shape.x += this.vX; this.shape.y += this.vY; //Keep the sprite within the window if( this.shape.x - this.radius < 0){ this.vX = -this.vX; } if( this.shape.y - this.radius < 0){ this.vY = -this.vY; } if( this.shape.x + this.radius > window.nativeWindow.stage.stageWidth){ DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 71 Trabalhar com janelas nativas this.vX = -this.vX; } if( this.shape.y + this.radius > window.nativeWindow.stage.stageHeight){ this.vY = -this.vY; } }; } function init(){ //turn off the default HTML background window.htmlLoader.paintsDefaultBackground = false; var bottom = new Bouncer(60,0xff2233); var top = new Bouncer(30,0x2441ff); //listen for the enterFrame event window.htmlLoader.addEventListener("enterFrame",function(evt){ bottom.update(); top.update(); }); //add the bouncing shapes to the window stage window.nativeWindow.stage.addChildAt(bottom.shape,0); window.nativeWindow.stage.addChild(top.shape); } </script> <body onload="init();"> <h1>de Finibus Bonorum et Malorum</h1> <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p> <p style="background-color:#FFFF00; color:#660000;">This paragraph has a background color.</p> <p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.</p> </body> </html> Este exemplo faz uma introdução rudimentar a algumas técnicas avançadas que cruzam os limites entre o JavaScript e o ActionScript no AIR. Se não estiver familiarizado com o uso de objetos de exibição do ActionScript, consulte a seção Programação da exibição, do guiaProgramação do Adobe ActionScript 3.0 para obter mais informações. Exemplo: Criação de uma janela nativa O exemplo abaixo mostra como criar uma janela nativa: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 72 Trabalhar com janelas nativas public function createNativeWindow():void { //create the init options var options:NativeWindowInitOptions = new NativeWindowInitOptions(); options.transparent = false; options.systemChrome = NativeWindowSystemChrome.STANDARD; options.type = NativeWindowType.NORMAL; //create the window var newWindow:NativeWindow = new NativeWindow(options); newWindow.title = "A title"; newWindow.width = 600; newWindow.height = 400; newWindow.stage.align = StageAlign.TOP_LEFT; newWindow.stage.scaleMode = StageScaleMode.NO_SCALE; //activate and show the new window newWindow.activate(); } Gerenciamento de janelas Use as propriedades e os métodos da classe NativeWindow para gerenciar a aparência, o comportamento e o ciclo de vida das janelas de área de trabalho. Obter uma ocorrência de NativeWindow Para manipular uma janela, primeiro você deve obter a ocorrência dela. A ocorrência da janela pode ser obtida em um dos seguintes lugares: • O construtor nativo de janela usado para criar a janela: var win:NativeWindow = new NativeWindow(initOptions); • A propriedade nativeWindow do estágio da janela: var win:NativeWindow = stage.nativeWindow; • A propriedade stage de um objeto de exibição na janela: var win:NativeWindow = displayObject.stage.nativeWindow; • A propriedade target de um evento de janela nativa despachada pela janela: private function onNativeWindowEvent(event:NativeWindowBoundsEvent):void { var win:NativeWindow = event.target as NativeWindow; } • A propriedade nativeWindow de uma página HTML exibida na janela: var win:NativeWindow = htmlLoader.window.nativeWindow; • As propriedades activeWindow e openedWindows do objeto NativeApplication: var nativeWin:NativeWindow = NativeApplication.nativeApplication.activeWindow; var firstWindow:NativeWindow = NativeApplication.nativeApplication.openedWindows[0]; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 73 Trabalhar com janelas nativas NativeApplication.nativeApplication.activeWindow faz referência à janela ativa de um aplicativo (mas retorna null se a janela ativa não é uma janela deste aplicativo do AIR). A matriz NativeApplication.nativeApplication.openedWindows contém todas as janelas de um aplicativo do AIR que não foram fechadas. Ativar, mostrar e ocultar janelas Para ativar uma janela, chame o método activate() de NativeWindow. A ativação de uma janela a traz para frente, dá a ela foco do teclado e do mouse e, se necessário, a torna visível mediante a restauração da janela ou a definição da propriedade visible como true. A ativação de uma janela não altera a ordem de outras janelas do aplicativo. A chamada do método activate() faz com que a janela despache um evento activate. Para mostrar uma janela oculta sem ativá-la, defina a propriedade visible como true. Isso traz a janela para frente, mas não atribui o foco para ela. Para ocultar uma janela de forma que não seja exibida, defina sua propriedade visible como false. Ocultar uma janela suprime a exibição tanto da janela quanto de qualquer ícone relacionado na barra de tarefas e, no Mac OS X, a entrada no menu Janelas. Nota: No Mac OS X, não é possível ocultar totalmente uma janela minimizada que tenha um ícone na parte de janela do encaixe. Se a propriedade visible está definida como false em uma janela minimizada, o ícone de encaixe da janela continua sendo exibido. Se o usuário clica no ícone, a janela é restaurada para um estado visível e exibida. Alteração da ordem de exibição de janelas O AIR oferece diversos métodos para alterar diretamente a ordem de exibição das janelas. É possível mover uma janela para o começo ou o final da ordem de exibição, bem como colocar uma janela em cima de outra ou atrás dela. Ao mesmo tempo, o usuário pode reordenar as janelas ativando-as. Você pode manter uma janela em frente de outras definindo sua propriedade alwaysInFront como true. Se mais de uma janela tiver essa configuração, a ordem de exibição dessas janelas será definida entre elas, mas sempre serão organizadas acima das janelas cuja propriedade alwaysInFront está definida como false. As janelas que estão no primeiro grupo também são exibidas acima das janelas de outros aplicativos, mesmo quando o aplicativo do AIR não está ativo. Como esse comportamento pode interromper o trabalho do usuário, definir alwaysInFront como true é algo que só deve ser feito quando necessário e apropriado. Os exemplos de usos justificados incluem: • Janelas pop-up temporárias de controles, como dicas de ferramentas, listas pop-up, menus personalizados e caixas de combinação. Como essas janelas devem ser fechadas quando perdem o foco, pode-se evitar a dor de cabeça de impedir um usuário de ver outra janela. • Mensagens de erro e alertas extremamente urgentes. Quando pode ocorrer uma alteração irrevogável se o usuário não responde de imediato, pode ser justificável trazer uma janela de alerta para frente. No entanto, a maioria dos erros e alertas pode ser tratada na ordem de exibição normal das janelas. • Janelas pop-up de curta duração. Nota: O AIR não impõe o uso apropriado da propriedade alwaysInFront. Entretanto, se o seu aplicativo interrompe o fluxo de trabalho de um usuário, possivelmente será enviado para a lixeira desse mesmo usuário. A classe NativeWindow oferece estas propriedades e métodos para definir a ordem de exibição de uma janela em relação a outras janelas: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 74 Trabalhar com janelas nativas Membro Descrição propriedade alwaysInFront Especifica se a janela é exibida no primeiro grupo de janelas. Em quase todos os casos, false é a melhor configuração. Alterar o valor de false para true traz a janela para frente de todas as janelas (mas não a ativa). Alterar o valor de true para false coloca a janela atrás das demais janelas do primeiro grupo, mas ainda na frente de outras. Definir a propriedade de uma janela com seu valor atual não altera a ordem de exibição. orderToFront() Traz a janela para frente. orderInFrontOf() Coloca a janela diretamente à frente de uma determinada janela. orderToBack() Envia a janela para trás de outras janelas. orderBehind() Coloca a janela diretamente atrás de uma determinada janela. activate() Traz a janela para frente (além de torná-la visível e de lhe atribuir foco). Nota: Se uma janela está oculta (visible é false) ou minimizada, chamar os métodos de ordem de exibição não surte nenhum efeito. No sistema operacional Linux, diferentes gerenciadores de janela forçam regras diferentes, dependendo da ordem de exibição da janela: • Em alguns gerenciadores de janela, as janelas do utilitário são sempre exibidas em frente às janelas normais. • Em alguns gerenciadores de janela, uma janela de tela cheia com alwaysInFront definida como true é sempre exibida na frente de outras janelas que também tenham alwaysInFront definida como true. Fechamento de janelas Para fechar uma janela, use o método NativeWindow.close(). Fechar uma janela descarrega o conteúdo dela; porém, se outros objeto tiverem referências a esse conteúdo, os objetos de conteúdo não serão destruídos. O método NativeWindow.close() é executado de forma assíncrona, e o aplicativo que está contido na janela continua a executar durante o processo de fechamento. O método close despacha um evento close quando a operação de fechamento é concluída. O objeto NativeWindow ainda é tecnicamente válido, mas o acesso à maioria das propriedades e dos métodos em uma janela fechada gera IllegalOperationError. Não é possível reabrir uma janela fechada. Verifique a propriedade closed de uma janela para testar se a janela foi fechada. Para simplesmente ocultar a exibição de uma janela, defina a propriedade NativeWindow.visible como false. Se a propriedade Nativeapplication.autoExit é true, o padrão, o aplicativo é encerrado ao ser fechada sua última janela. Permitir o cancelamento de operações de janela Quando uma janela usa o cromo do sistema, a interação do usuário com ela pode ser cancelada monitorando ou cancelando o comportamento padrão dos eventos apropriados. Por exemplo, quando um usuário clica no botão Fechar do cromo do sistema, o evento closing é despachado. Se algum ouvinte registrado chamar o método preventDefault() do evento, a janela não será fechada. Quando uma janela não usa o cromo do sistema, os eventos de notificação referentes às alterações pretendidas não são despachados automaticamente antes de a alteração ser feita. Por isso, se você chamar os métodos para fechar uma janela ou se alterar o estado dela ou definir qualquer uma das propriedades de limites de janela, a alteração não poderá ser cancelada. Para notificar os componentes do seu aplicativo antes que seja feita uma alteração de janela, a lógica do aplicativo poderá despachar o evento de notificação relevante usando o método dispatchEvent() da janela. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 75 Trabalhar com janelas nativas Por exemplo, a seguinte lógica implementa um manipulador de eventos cancelável para o botão Fechar de uma janela: public function onCloseCommand(event:MouseEvent):void{ var closingEvent:Event = new Event(Event.CLOSING,true,true); dispatchEvent(closing); if(!closingEvent.isDefaultPrevented()){ win.close(); } } O método dispatchEvent() retorna false se o método preventDefault() do evento é chamado por um ouvinte. No entanto, ele também pode retornar false por outros motivos, portanto é melhor usar o método isDefaultPrevented() explicitamente para testar se a alteração deve ser cancelada. Maximização, minimização e restauração de uma janela Para maximizar a janela, use o método maximize() da classe NativeWindow. myWindow.maximize(); Para minimizar a janela, use o método minimize() de NativeWindow. myWindow.minimize(); Para restaurar a janela (isto é, colocá-la novamente no tamanho em que estava antes de ser minimizada ou maximizada), use o método restore() de NativeWindow. myWindow.restore(); Nota: O comportamento resultante da maximização de uma janela do AIR é diferente do comportamento padrão do Mac OS X. Em vez de alternar entre um tamanho “padrão” definido pelo aplicativo e o último tamanho definido pelo usuário, as janelas do AIR alternam entre o último tamanho definido pelo aplicativo ou pelo usuário e a área útil total da tela. No sistema operacional Linux, diferentes gerenciadores de janela forçam regras diferentes com relação a configuração do estado de exibição da janela: • Em alguns gerenciadores de janela, não é possível maximizar as janelas dos utilitários. • Se um tamanho máximo for definido para a janela, algumas janelas não permitirão a maximização. Alguns outros gerenciadores de janela definem o estado de exibição como maximizado, mas não redimensionam a janela. Em qualquer um dos casos, não é despachado nenhum evento de alteração do estado de exibição. • Alguns gerenciadores de janela não cumprem as configurações maximizable ou minimizable de janela. Exemplo: Minimização, maximização, restauração e fechamento de uma janela O seguinte exemplo do ActionScript para Flash cria quatro campos de texto clicáveis que acionam os métodos minimize(), maximize(), restore() e close() de NativeWindow: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 76 Trabalhar com janelas nativas package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.text.TextField; public class MinimizeExample extends Sprite { public function MinimizeExample():void { var minTextBtn:TextField = new TextField(); minTextBtn.x = 10; minTextBtn.y = 10; minTextBtn.text = "Minimize"; minTextBtn.background = true; minTextBtn.border = true; minTextBtn.selectable = false; addChild(minTextBtn); minTextBtn.addEventListener(MouseEvent.CLICK, onMinimize); var maxTextBtn:TextField = new TextField(); maxTextBtn.x = 120; maxTextBtn.y = 10; maxTextBtn.text = "Maximize"; maxTextBtn.background = true; maxTextBtn.border = true; maxTextBtn.selectable = false; addChild(maxTextBtn); maxTextBtn.addEventListener(MouseEvent.CLICK, onMaximize); var restoreTextBtn:TextField = new TextField(); restoreTextBtn.x = 230; restoreTextBtn.y = 10; restoreTextBtn.text = "Restore"; restoreTextBtn.background = true; restoreTextBtn.border = true; restoreTextBtn.selectable = false; addChild(restoreTextBtn); restoreTextBtn.addEventListener(MouseEvent.CLICK, onRestore); var closeTextBtn:TextField = new TextField(); closeTextBtn.x = 340; closeTextBtn.y = 10; closeTextBtn.text = "Close Window"; closeTextBtn.background = true; closeTextBtn.border = true; closeTextBtn.selectable = false; addChild(closeTextBtn); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 77 Trabalhar com janelas nativas closeTextBtn.addEventListener(MouseEvent.CLICK, onCloseWindow); } function onMinimize(event:MouseEvent):void { this.stage.nativeWindow.minimize(); } function onMaximize(event:MouseEvent):void { this.stage.nativeWindow.maximize(); } function onRestore(event:MouseEvent):void { this.stage.nativeWindow.restore(); } function onCloseWindow(event:MouseEvent):void { this.stage.nativeWindow.close(); } } } Redimensionamento e movimentação de uma janela Quando uma janela usa o cromo do sistema, o cromo oferece controles de arrastar que permitem redimensionar a janela e movimentá-la na área de trabalho. Se uma janela não usa o cromo do sistema, adicione seus próprios controles para que o usuário possa redimensionar e movimentar a janela. Nota: Para redimensionar ou movimentar uma janela, primeiro você deve obter uma referência à ocorrência de NativeWindow. Para mais informações sobre como obter uma referência à janela, consulte “Obter uma ocorrência de NativeWindow” na página 72. Redimensionamento de uma janela Para permitir que um usuário redimensione uma janela de forma interativa, use o método NativeWindowstartResize(). Quando esse método é chamado a partir de um evento mouseDown, a operação de redimensionamento é orientada pelo mouse e executada quando o sistema operacional recebe um evento mouseUp. Quando chama startResize(), você passa um argumento que especifica a borda ou o canto a partir do qual a janela deve ser redimensionada. Para definir o tamanho das janelas de forma programática, defina as propriedades width, height ou bounds da janela nas dimensões desejadas. Quando você define os limites, o tamanho da janela e a posição podem ser alterados ao mesmo tempo., No entanto, não há garantias da ordem de exibição das alterações. Alguns gerenciadores de janela do Linux não permitem que janelas se estendam além dos limites da tela da área de trabalho. Nesses casos, o tamanho final da janela pode ser limitado devido à ordem em que as propriedades são definidas, apesar de as alterações resultarem em uma janela legal. Por exemplo, se você alterar a altura e a posição y de uma janela perto da parte inferior da tela, a alteração na altura total pode não ocorrer quando for aplicada antes da alteração na posição y. Nota: No Linux, as propriedades da janela são alteradas de forma assíncrona. Se você definir uma propriedade em uma linha do programa e ler os valores na linha seguinte, o valor lido ainda refletirá a configuração antiga. Você pode usar os eventos gerados pela janela para detectar quando a alteração é aplicada. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 78 Trabalhar com janelas nativas O modo de dimensionamento do palco determina o comportamento do palco da janela e de seu conteúdo quando uma janela é redimensionada. Lembre-se de que os modos de dimensionamento de palco devem ser usados em situações em que o aplicativo não tem controle sobre o tamanho ou a proporção de seu espaço de exibição, como é o caso de um navegador da Web. Em geral, os melhores resultados são obtidos quando você define a propriedade scaleMode do palco como StageScaleMode.NO_SCALE. Para que o conteúdo da janela seja dimensionado, também é possível definir os parâmetros do conteúdo scaleX e scaleY em resposta às alterações nos limites da janela. Movimentação de uma janela Para movimentar uma janela sem redimensioná-la, use o método startMove() de NativeWindow. Da mesma forma que ocorre com o método startResize(), quando você chama o método startMove() a partir de um evento mouseDown, o processo de movimentação é orientado pelo mouse e executado quando o sistema operacional recebe um evento mouseUp. Para obter mais informações sobre os métodos startResize() e startMove(), consulte a Referência dos componentes e da linguagem do ActionScript 3.0 (http://www.adobe.com/go/learn_air_aslr_br). Exemplo: Redimensionamento e movimentação de janelas O exemplo abaixo mostra como iniciar operações de redimensionamento e movimentação em uma janela: package { import flash.display.Sprite; import flash.events.MouseEvent; import flash.display.NativeWindowResize; public class NativeWindowResizeExample extends Sprite { public function NativeWindowResizeExample():void { // Fills a background area. this.graphics.beginFill(0xFFFFFF); this.graphics.drawRect(0, 0, 400, 300); this.graphics.endFill(); // Creates a square area where a mouse down will start the resize. var resizeHandle:Sprite = createSprite(0xCCCCCC, 20, this.width - 20, this.height - 20); resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartResize); // Creates a square area where a mouse down will start the move. var moveHandle:Sprite = createSprite(0xCCCCCC, 20, this.width - 20, 0); moveHandle.addEventListener(MouseEvent.MOUSE_DOWN, onStartMove); } public function createSprite(color:int, size:int, x:int, y:int):Sprite { var s:Sprite = new Sprite(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 79 Trabalhar com janelas nativas s.graphics.beginFill(color); s.graphics.drawRect(0, 0, size, size); s.graphics.endFill(); s.x = x; s.y = y; this.addChild(s); return s; } public function onStartResize(event:MouseEvent):void { this.stage.nativeWindow.startResize(NativeWindowResize.BOTTOM_RIGHT); } public function onStartMove(event:MouseEvent):void { this.stage.nativeWindow.startMove(); } } } Monitorando eventos de janela Para monitorar os eventos despachados por uma janela, registre um ouvinte na ocorrência da janela. Por exemplo, para monitorar o evento closing, registre um ouvinte na janela, da seguinte maneira: myWindow.addEventListener(Event.CLOSING, onClosingEvent); Quando um evento é despachado, a propriedade target faz referência à janela que o está enviando. A maioria dos eventos de janela tem duas mensagens relacionadas. A primeira mensagem sinaliza que uma alteração de janela é iminente (e pode ser cancelada), enquanto a segunda indica que a alteração foi executada. Por exemplo, quando um usuário clica no botão Fechar de uma janela, a mensagem do evento closing é despachada. Se nenhum ouvinte cancelar o evento, a janela será fechada e o evento close será despachado para qualquer ouvinte. Normalmente, os eventos de aviso, como closing, só são despachados quando o cromo do sistema foi usado para acionar um evento. Se você chamar o método de janela close(), por exemplo, o evento closing não será despachado automaticamente (será despachado apenas o evento close). No entanto, você pode construir um objeto de evento closing e despachá-lo usando o método de janela dispatchEvent(). Os eventos de janela que despacham um objeto Event são: Evento Descrição activate Despachado quando a janela recebe foco. deactivate Despachado quando a janela perde foco. closing Despachado quando a janela está prestes a fechar. Este evento só ocorre automaticamente quando o botão Fechar do cromo do sistema é pressionado ou, no Mac OS X, quando é chamado o comando Quit. close Despachado quando a janela foi fechada. Os eventos de janela que despacham um objeto NativeWindowBoundsEvent são: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 80 Trabalhar com janelas nativas Evento Descrição moving Despachado imediatamente depois que o canto superior esquerdo da janela muda de posição, seja como resultado da movimentação, do redimensionamento ou da alteração do estado de exibição da janela. move Despachado depois que a posição do canto superior esquerdo é alterada. resizing Despachado imediatamente antes de a largura ou a altura da janela ser alterada, seja como resultado do redimensionamento ou de uma alteração no estado de exibição. resize Despachado após uma alteração no tamanho da janela. Para eventos NativeWindowBoundsEvent, você pode usar as propriedades beforeBounds e afterBounds para determinar os limites da janela antes e depois da alteração iminente ou concluída. Os eventos de janela que despacham um objeto NativeWindowDisplayStateEvent são: Evento Descrição displayStateChanging Despachado imediatamente antes de uma alteração no estado de exibição da janela. displayStateChange Despachado depois que o estado de exibição da janela foi alterado. Para eventos NativeWindowDisplayStateEvent , você pode usar as propriedades beforeDisplayState e afterDisplayState para determinar o estado de exibição da janela antes e depois da alteração iminente ou concluída. Em alguns gerenciadores de janela do Linux, um evento de alteração do estado de exibição não é despachado quando uma janela com uma configuração de tamanho máximo é maximizada. (A janela é definida como estado de exibição máximo, mas não é redimensionada). Exibição de janelas em tela cheia Definir a propriedade displayState da classe Stage como StageDisplayState.FULL_SCREEN_INTERACTIVE coloca a janela em modo de tela cheia, que permite entrada pelo teclado. (No conteúdo SWF em execução em um navegador, a entrada pelo teclado não é permitida). Para sair do modo de tela cheia, o usuário deve pressionar a tecla Escape. Nota: Alguns gerenciadores de janela do Linux não alterarão as dimensões de janela para encher a tela, caso um tamanho máximo seja definido para a janela (mas removerão o cromo do sistema da janela). O seguinte exemplo do ActionScript para Flash simula um terminal de texto simples em tela cheia: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 81 Trabalhar com janelas nativas import import import import flash.display.Sprite; flash.display.StageDisplayState; flash.text.TextField; flash.text.TextFormat; public class FullScreenTerminalExample extends Sprite { public function FullScreenTerminalExample():void { var terminal:TextField = new TextField(); terminal.multiline = true; terminal.wordWrap = true; terminal.selectable = true; terminal.background = true; terminal.backgroundColor = 0x00333333; this.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; addChild(terminal); terminal.width = 550; terminal.height = 400; terminal.text = "Welcome to the dumb terminal application. Press the ESC key to exit.\n_"; var tf:TextFormat = new TextFormat(); tf.font = "Courier New"; tf.color = 0x00CCFF00; tf.size = 12; terminal.setTextFormat(tf); terminal.setSelection(terminal.text.length - 1, terminal.text.length); } } 82 Capítulo 11: Telas Use a classe Screen do Adobe® AIR® para acessar informações sobre as telas de exibição da área de trabalho anexadas a um computador. Informações on-line adicionais sobre telas Você pode encontrar mais informações sobre a classe Screen e sobre o trabalho com telas nestas fontes: Início rápido (Adobe AIR Developer Connection) • Medida da área de trabalho virtual Referência de linguagem • Screen Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (pesquisar por 'AIR screens') Noções básicas de tela A API de tela contém uma classe única, Screen, que oferece membros estáticos para obter informações de tela do sistema e membros de ocorrência para descrever uma tela específica. Um sistema de computador pode ter vários monitores ou exibições anexadas, que podem corresponder a diversas telas da área de trabalho organizadas em um espaço virtual. A classe Screen do AIR fornece informações sobre as telas, sua organização relativa e seu espaço utilizável. Se mais de um monitor for mapeado para a mesma tela, haverá somente uma tela. Se o tamanho da tela é maior que a área de exibição do monitor, não há como determinar que parte da tela está visível atualmente A tela representa uma área de exibição independente da área de trabalho. As telas são descritas como retângulos na área de trabalho virtual. O canto superior esquerdo da tela designado como exibição principal é a origem do sistema de coordenadas da área de trabalho virtual. Todos os valores usados para descrever a tela são fornecidos em pixels. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 83 Telas Limites da tela Tela virtual Limites utilizáveis Nessa organização de telas, há duas telas na área de trabalho virtual. As coordenadas do canto superior esquerdo da tela principal (nº1) são sempre (0,0). Se a organização da tela for alterada para designar a tela nº 2 como tela principal, as coordenadas da tela nº 1 se tornarão negativas. Barras de menu, barras de tarefa e encaixes são excluídos ao reportar limites utilizáveis de uma tela. Para obter informações detalhadas sobre classe, métodos, propriedades e eventos da API da tela, consulte a Referência dos componentes e da linguagem do ActionScript 3.0 (http://www.adobe.com/go/learn_air_aslr_br). Enumeração de telas Você pode enumerar as telas da área de trabalho virtual com os seguintes métodos e propriedades de tela: Método ou Propriedade Descrição Screen.screens Oferece uma matriz de objetos Screen que descreve as telas disponíveis. Observe que a ordem da matriz não é significativa. Screen.mainScreen Oferece o objeto Screen da tela principal. No Mac OS X, a tela principal é a tela que exibe a barra de menu. No Windows, a tela principal é a tela primária designada pelo sistema. Screen.getScreensForRectangle() Oferece uma matriz de objetos Screen que descreve as telas intersectadas pelo retângulo determinado. O retângulo passado para este método está em coordenadas de pixel na área de trabalho virtual. Se nenhuma tela intersectar o retângulo, a matriz ficará vazia. Você pode usar esse método para descobrir em que telas a janela é exibida. Você não deve salvar os valores retornados pelos métodos e propriedades da classe Screen. O usuário ou sistema operacional pode alterar as telas disponíveis e a respectiva disposição a qualquer momento. O exemplo a seguir usa a API da tela para mover uma janela entre várias telas em resposta ao pressionamento das teclas de seta. Para mover a janela para a próxima tela, o exemplo obtém a matriz screens e a classifica verticalmente ou horizontalmente (dependendo da tecla de seta pressionada). Em seguida, o código passa pela matriz classificada, comparando cada tela com as coordenadas da tela atual. Para identificar a tela atual da janela, o exemplo chama Screen.getScreensForRectangle(), passando nos limites da janela. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 84 Telas package { import import import import import import flash.display.Sprite; flash.display.Screen; flash.events.KeyboardEvent; flash.ui.Keyboard; flash.display.StageAlign; flash.display.StageScaleMode; public class ScreenExample extends Sprite { public function ScreenExample() { stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.addEventListener(KeyboardEvent.KEY_DOWN,onKey); } private function onKey(event:KeyboardEvent):void{ if(Screen.screens.length > 1){ switch(event.keyCode){ case Keyboard.LEFT : moveLeft(); break; case Keyboard.RIGHT : moveRight(); break; case Keyboard.UP : moveUp(); break; case Keyboard.DOWN : moveDown(); break; } } } private function moveLeft():void{ var currentScreen = getCurrentScreen(); var left:Array = Screen.screens; left.sort(sortHorizontal); for(var i:int = 0; i < left.length - 1; i++){ if(left[i].bounds.left < stage.nativeWindow.bounds.left){ stage.nativeWindow.x += left[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top; } } } private function moveRight():void{ var currentScreen:Screen = getCurrentScreen(); var left:Array = Screen.screens; left.sort(sortHorizontal); for(var i:int = left.length - 1; i > 0; i--){ if(left[i].bounds.left > stage.nativeWindow.bounds.left){ stage.nativeWindow.x += DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 85 Telas left[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += left[i].bounds.top - currentScreen.bounds.top; } } } private function moveUp():void{ var currentScreen:Screen = getCurrentScreen(); var top:Array = Screen.screens; top.sort(sortVertical); for(var i:int = 0; i < top.length - 1; i++){ if(top[i].bounds.top < stage.nativeWindow.bounds.top){ stage.nativeWindow.x += top[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += top[i].bounds.top - currentScreen.bounds.top; break; } } } private function moveDown():void{ var currentScreen:Screen = getCurrentScreen(); var top:Array = Screen.screens; top.sort(sortVertical); for(var i:int = top.length - 1; i > 0; i--){ if(top[i].bounds.top > stage.nativeWindow.bounds.top){ stage.nativeWindow.x += top[i].bounds.left - currentScreen.bounds.left; stage.nativeWindow.y += top[i].bounds.top - currentScreen.bounds.top; break; } } } private function sortHorizontal(a:Screen,b:Screen):int{ if (a.bounds.left > b.bounds.left){ return 1; } else if (a.bounds.left < b.bounds.left){ return -1; } else {return 0;} } private function sortVertical(a:Screen,b:Screen):int{ if (a.bounds.top > b.bounds.top){ return 1; } else if (a.bounds.top < b.bounds.top){ return -1; } else {return 0;} } private function getCurrentScreen():Screen{ var current:Screen; var screens:Array = Screen.getScreensForRectangle(stage.nativeWindow.bounds); (screens.length > 0) ? current = screens[0] : current = Screen.mainScreen; return current; } } } 86 Capítulo 12: Trabalho com menus nativos Use as classes na API de menu nativo para definir aplicativo, janela, contexto e menus pop-up. Informações online adicionais sobre menus nativos Você pode encontrar mais informações sobre a API de menu nativo e trabalho com menus nativos nestas fontes: Início rápido (Adobe AIR Developer Connection) • Adição de menus nativos a um aplicativo AIR Referência de linguagem • NativeMenu • NativeMenuItem Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (pesquisar por 'AIR menus') Noções básicas do menu AIR As classes de menu nativo permitem acessar os recursos do menu nativo do sistema operacional em que o aplicativo está sendo executado. Objetos NativeMenu podem ser usados em menus de aplicativo (disponíveis no Mac OS X), menus de janela (disponíveis no Windows e no Linux), menus de contexto e menus pop-up. Classes de menu AIR As classes de menu Adobe® AIR™ incluem: Pacote Classes flash.display • NativeMenu • NativeMenuItem • ContextMenu • ContextMenuItem • Evento • ContextMenuEvent flash.ui flash.events DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 87 Trabalho com menus nativos Variedades de menu O AIR oferece suporte aos seguintes tipos de menus: Menus de aplicativo O menu de aplicativo é um menu global aplicável ao aplicativo inteiro. Há suporte para menus de aplicativo no Mac OS X, mas não no Windows nem no Linux. No Mac OS X , o sistema operacional cria automaticamente o menu de aplicativo. Você pode usar a API de menu AIR para adicionar itens e submenus aos menus padrão. Você pode adicionar ouvintes para tratar os comandos de menu existentes. Ou você pode remover itens existentes. Menus de janela O menu de janela está associado a uma única janela e é exibido abaixo da barra de título. Os menus podem ser adicionados a uma janela, criando um objeto NativeMenu e atribuindo-o à propriedade menu do objeto NativeWindow. Há suporte para menus de janela nos sistemas operacionais Windows e Linux, mas não no Mac OS X. Menus de janela nativos só podem ser usados em janelas com o cromo do sistema. Menus de contexto Os menus de contexto são exibidos em resposta ao clique com o botão direito do mouse ou ao clique com a tecla Command pressionada em um objeto interativo no conteúdo SWF ou um elemento de documento no conteúdo HTML. Você pode criar um menu de contexto usando a classe NativeMenu ou ContextMenu. No conteúdo HTML, você pode usar as APIs de kit da Web HTML e JavaScript para adicionar menus de contexto a elementos HTML. Menus de ícone de bandeja do sistema e de encaixe Esses menus de ícone são semelhantes aos menus de contexto e são atribuídos a um ícone de aplicativo no encaixe do Mac OS X ou nas áreas de notificação do Windows ou do Linux, na barra de tarefas. Menus de ícone da bandeja do sistema e de encaixe usam a classe NativeMenu. No Mac OS X, os itens no menu são adicionados acima dos itens padrão do sistema operacional. Não há menu padrão no Windows nem no Linux. Menus pop-up O menu pop-up AIR é semelhante ao menu de contexto, mas não está necessariamente associado a um objeto de aplicativo ou componente específico. Os menus pop-up podem ser exibidos em qualquer lugar na janela, chamando o método display() de qualquer objeto NativeMenu. Menus personalizados Menus nativos são inteiramente desenhados pelo sistema operacional e, como tal, estão presentes fora dos modelos de processamento Flash e HTML. Você tem liberdade para criar seus próprios menus não nativos usando MXML, ActionScript ou JavaScript. As classes de menu AIR não oferecem nenhuma facilidade para controlar os desenhos de menus nativos. Menus padrão Os menus padrão a seguir são fornecidos pelo sistema operacional ou uma classe incorporada do AIR: • Menu de aplicativo no Mac OS X • Menu de ícone de encaixe no Mac OS X • Menu de contexto de textos e imagens selecionados em conteúdo HTML • Menu de contexto de texto selecionado no objeto TextField (ou em um objeto que estende o TextField) Estrutura de menu Os menus são de natureza hierárquica. Os objetos NativeMenu contêm objetos-filho NativeMenuItem. Os objetos NativeMenuItem que representam submenus, por sua vez, podem conter objetos NativeMenu. O objeto de menu de nível superior ou raiz na estrutura representa a barra de menu de menus de aplicativo e janela. (Menus de contexto, ícone e pop-up não têm uma barra de menu). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 88 Trabalho com menus nativos O diagrama a seguir ilustra a estrutura de um menu típico. O menu raiz representa a barra de menu e contém dois itens de menu que fazem referência ao submenu File e ao submenu Edit. O submenu Arquivo nessa estrutura contém dois itens de comando e um item que faz referência ao submenu Open Recent Menu, que contém, ele mesmo, três itens. O submenu Edit contém três comandos e um separador. NativeMenu Menu de raiz NativeMenuItem NativeMenu “Arquivo” Menu Arquivo NativeMenuItem “Novo” NativeMenuItem “Salvar” NativeMenuItem “Abrir recente” NativeMenu NativeMenuItem NativeMenu Menu Abrir recente NativeMenuItem “GreatGatsby.pdf” NativeMenuItem “WarAndPeace.pdf” NativeMenuItem “Iliad.pdf” “Editar” Menu Editar NativeMenuItem “Copiar” NativeMenuItem “Colar” NativeMenuItem Separador NativeMenuItem “Preferências” Definir um submenu requer um objeto NativeMenu e um objeto NativeMenuItem. O objeto NativeMenuItem define o rótulo exibido no menu pai e permite ao usuário abrir o submenu. O objeto NativeMenu funciona como um recipiente de itens no submenu. O objeto NativeMenuItem se refere ao objeto NativeMenu pela propriedade submenu NativeMenuItem. Para exibir um exemplo de código que cria esse menu, consulte “Exemplo: Menu de janela e aplicativo” na página 98. Eventos menu Os objetos NativeMenu e NativeMenuItem despacham os eventos displaying e select: Displaying: Imediatamente antes de o menu ser exibido, o menu e os respectivos itens de menu despacham o evento displaying para qualquer ouvinte registrado. O evento displaying dá a oportunidade de atualizar o conteúdo de menu ou a aparência do item antes de ele ser mostrado ao usuário. Por exemplo, no ouvinte do evento displaying do menu “Open Recent”, você pode alterar os itens de menu para que reflitam a lista atual de documentos exibidos recentemente. A propriedade target do objeto event é sempre o menu que está para ser exibido. O currentTarget é o objeto em que o ouvinte está registrado: o próprio menu ou um de seus itens. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 89 Trabalho com menus nativos Nota: O evento displaying também é despachado sempre que o estado do menu ou de um de seus itens for acessado. Select: Quando um item de comando é escolhido pelo usuário, o item despacha um evento select para qualquer ouvinte registrado. Itens de submenu e separadores não podem ser selecionados, portanto, nunca despacham um evento select. O evento select surge em bolha de um item de menu para o menu que o contém, em cima do menu raiz. Você pode ouvir eventos select diretamente em um item e pode ouvir mais acima na estrutura de menu. Quando você ouvir o evento select em um menu, poderá identificar o item selecionado usando a propriedade target do evento. Conforme o evento surge em bolha pela hierarquia de menu, a propriedade currentTarget do objeto event identifica o objeto de menu atual. Nota: Os objetos ContextMenu e ContextMenuItem despacham eventos menuItemSelect e menuSelect, bem como eventos select e displaying. Equivalentes de tecla de comandos de menu Você pode atribuir um equivalente de tecla (às vezes chamado de acelerador) em um comando de menu. O item do menu despacha o evento select para qualquer ouvinte registrado quando a tecla ou combinação de teclas é pressionada. O menu que contém o item deve ser parte do menu do aplicativo ou a janela ativa do comando que deve ser chamado. Os equivalentes de tecla têm duas partes, uma seqüência representando a tecla primária e uma matriz de teclas do modificador, que também devem ser pressionadas. Para atribuir a tecla primária, defina a propriedade keyEquivalent do item de menu para a seqüência de caractere único dessa tecla. Se você usar uma letra maiúscula, a tecla Shift é adicionada à matriz do modificador automaticamente. No Mac OS X, o modificador padrão é a tecla Command (Keyboard.COMMAND). No Windows e no Linux, é a tecla Control (Keyboard.CONTROL). Essas teclas padrão são adicionadas automaticamente à matriz do modificador. Para atribuir teclas do modificador diferentes, atribua uma nova matriz contendo os códigos de tecla desejados à propriedade keyEquivalentModifiers. A matriz padrão é sobrescrita. Se você usar os modificadores padrão ou atribuir a sua própria matriz de modificador, a tecla Shift será adicionada, se a seqüência atribuída à propriedade keyEquivalent for uma letra maiúscula. As constantes dos códigos de tecla para usar nas teclas do modificador são definidas na classe Keyboard. A seqüência de equivalente de tecla atribuída é exibida automaticamente ao lado no nome do item de menu. O formato depende do sistema operacional do usuário e das preferências do sistema. Nota: Se você atribuir o valor Keyboard.COMMAND a uma matriz de modificador de tecla no sistema operacional do Windows, nenhum equivalente de tecla será exibido no menu. No entanto, a tecla Control deve ser usada para ativar o comando de menu. O exemplo a seguir atribui Ctrl+Shift+G como equivalente de tecla de um item de menu: var item:NativeMenuItem = new NativeMenuItem("Ungroup"); item.keyEquivalent = "G"; Este exemplo atribui Ctrl+Shift+G como equivalente de tecla, definindo diretamente a matriz do modificador: var item:NativeMenuItem = new NativeMenuItem("Ungroup"); item.keyEquivalent = "G"; item.keyEquivalentModifiers = [Keyboard.CONTROL]; Nota: Os equivalentes de tecla só são ativados em menus de aplicativo e de janela. Se você adicionar um equivalente de tecla a um menu de contexto ou de pop-up, o equivalente de tecla é exibido no rótulo do menu, mas o comando de menu associado nunca será chamado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 90 Trabalho com menus nativos Mnemônicos Os mnemônicos são parte da interface de teclado do sistema operacional em menus. Linux, Mac OS X e Windows permitem a usuários abrir menus e selecionar comandos com o teclado, mas há diferenças sutis. No Mac OS X, o usuário digita a primeira ou as duas primeiras letras do menu ou comando e, em seguida, pressiona a tecla retornar. A propriedade mnemonicIndex é ignorada. No Windows, apenas uma única letra é significativa. Por padrão, a letra significativa é o primeiro caractere no rótulo, mas se você atribuir um mnemônico ao item de menu, o caractere significativo se torna a letra designada. Se dois itens em um menu têm o mesmo caractere significativo (quer um mnemônico tenha ou não sido atribuído), a interação de teclado do usuário com o menu muda um pouco. Em vez de pressionar uma única letra para selecionar o menu ou comando, o usuário deve pressionar a letra quantas vezes for necessário para realçar o item desejado e, em seguida, pressionar a tecla Enter para concluir a seleção. Para manter um comportamento consistente, você deve atribuir um mnemônico exclusivo a cada item no menu, em menus de janela. No Linux, nenhum mnemônico padrão é fornecido. Você deve especificar um valor para a propriedade mnemonicIndex de um item de menu para fornecer um mnemônico. Especifique o caractere mnemônico como índice na seqüência de rótulo. O índice do primeiro caractere em um rótulo é 0. Portanto, para usar "r" como o mnemônico de um item de menu rotulado, "Format", você deve definir a propriedade mnemonicIndex igual a 2. var item:NativeMenuItem = new NativeMenuItem("Format"); item.mnemonicIndex = 2; Estado do item de menu Os itens de menu têm duas propriedades de estados, marcados e ativados: marcado Defina como true para exibir uma marca de seleção ao lado do rótulo de item. var item:NativeMenuItem = new NativeMenuItem("Format"); item.checked = true; ativado Alterne o valor entre true e false para controlar se o comando está ativado. Itens desativados ficam visualmente “esmaecidos” e não despacham eventos select. var item:NativeMenuItem = new NativeMenuItem("Format"); item.enabled = false; Anexar objeto a um item de menu A propriedade data da classe NativeMenuItem permite fazer referência a um objeto arbitrário em cada item. Por exemplo, no menu "Open Recent", você pode atribuir o objeto File de cada documento a cada item do menu. var file:File = File.applicationStorageDirectory.resolvePath("GreatGatsby.pdf") var menuItem:NativeMenuItem = docMenu.addItem(new NativeMenuItem(file.name)); menuItem.data = file; Criação de menus nativos Este tópico descreve como criar os vários tipos de menu nativos suportados pelo AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 91 Trabalho com menus nativos Criação de objeto do menu raiz Para criar um objeto NativeMenu para servir como raiz do menu, use o construtor NativeMenu: var root:NativeMenu = new NativeMenu(); Em menus de aplicativo e janela, o menu raiz representa a barra de menu e deve conter apenas itens que abram submenus. Menus de contexto e pop-up não têm barra de menu, portanto, o menu raiz pode conter comandos e linhas separadoras, bem como submenus. Depois que o menu é criado, você pode adicionar itens de menu. Os itens aparecem no menu na ordem em que são adicionados, a menos que você os adicione em um índice específico, usando o método addItemAt() de um objeto de menu. Atribua o menu como aplicativo, janela, ícone ou menu de contexto ou exiba-o como menu pop-up, conforme mostrado nas seções a seguir: Configuração do menu de aplicativo NativeApplication.nativeApplication.menu = root; Nota: O Mac OS X define um menu contendo itens padrão para cada aplicativo. Atribuir um novo objeto NativeMenu à propriedade menu do objeto NativeApplication substitui o menu padrão. Você também pode usar o menu padrão, em vez de substitui-lo. Configuração de menu de janela nativeWindowObject.menu = root; Configuração de menu de contexto em um objeto interativo interactiveObject.contextMenu = root; Configuração de menu de ícone de encaixe DockIcon(NativeApplication.nativeApplication.icon).menu = root; Nota: O Mac OS X define um menu padrão para o ícone de encaixe do aplicativo. Ao atribuir um novo NativeMenu à propriedade de menu do objeto DockIcon, os itens nesse menu são exibidos acima dos itens padrão. Você não pode remover, acessar nem modificar os itens de menu padrão. Configuração de menu de ícone da bandeja do sistema. SystemTrayIcon(NativeApplication.nativeApplication.icon).menu = root; Exibição de menu como pop-up root.display(stage, x, y); Criação de submenu Para criar um submenu, você adiciona o objeto NativeMenuItem ao menu pai e, em seguida, atribui o objeto NativeMenu, definindo o submenu para a propriedade submenu do item. O AIR oferece duas maneiras de criar itens de submenu e respectivos objetos de menu associados: Você pode criar um item de menu e respectivo objeto de menu relacionado em uma etapa, com o método addSubmenu(): var editMenuItem:NativeMenuItem = root.addSubmenu(new NativeMenu(), "Edit"); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 92 Trabalho com menus nativos Você também pode criar o item de menu e atribuir separadamente o objeto de menu à respectiva propriedade submenu: var editMenuItem:NativeMenuItem = root.addItem("Edit", false); editMenuItem.submenu = new NativeMenu(); Criação de comando de menu Para criar um comando de menu, adicione o objeto NativeMenuItem a um menu e adicione um ouvinte de evento que faça referência à função que implementa o comando de menu: var copy:NativeMenuItem = new NativeMenuItem("Copy", false); copy.addEventListener(Event.SELECT, onCopyCommand); editMenu.addItem(copy); Você pode ouvir o evento select no próprio item de comando (conforme mostrado no exemplo) ou pode ouvir o evento select em um objeto de menu pai. Nota: Os itens de menu que representam submenus e linhas separadoras não despacham eventos select e, portanto, não podem ser usados como comandos. Criação de linha separadora de menu Para criar uma linha separadora, crie um NativeMenuItem, definindo o parâmetro isSeparator como true no construtor. Em seguida, adicione o item separador ao menu no local correto: var separatorA:NativeMenuItem = new NativeMenuItem("A", true); editMenu.addItem(separatorA); O rótulo especificado para o separador, se houver, não é exibido. Sobre menus de contexto No conteúdo SWF, qualquer objeto herdado de InteractiveObject pode ser determinado um menu de contexto atribuindo um objeto de menu à respectiva propriedade contextMenu. O objeto de menu atribuído ao contextMenu pode ser do tipo NativeMenu ou do tipo ContextMenu. Você pode ouvir eventos do menu nativo ou de menus contextuais ao usar as classes ContextMenu e ContextMenuItem; as duas são despachadas. Um benefício fornecido pelas propriedades do objeto ContextMenuEvent é que contextMenuOwner identifica o objeto ao qual o menu está associado e mouseTarget identifica o objeto que foi clicado para abrir o menu. Essas informações não estão disponíveis do objeto NativeMenuEvent. O exemplo a seguir cria um Sprite e adiciona um menu de contexto de edição simples: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 93 Trabalho com menus nativos var sprite:Sprite = new Sprite(); sprite.contextMenu = createContextMenu() private function createContextMenu():ContextMenu{ var editContextMenu:ContextMenu = new ContextMenu(); var cutItem:ContextMenuItem = new ContextMenuItem("Cut") cutItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, doCutCommand); editContextMenu.customItems.push(cutItem); var copyItem:ContextMenuItem = new ContextMenuItem("Copy") copyItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, doCopyCommand); editContextMenu.customItems.push(copyItem); var pasteItem:ContextMenuItem = new ContextMenuItem("Paste") pasteItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, doPasteCommand); editContextMenu.customItems.push(pasteItem); return editContextMenu } private function doCutCommand(event:ContextMenuEvent):void{trace("cut");} private function doCopyCommand(event:ContextMenuEvent):void{trace("copy");} private function doPasteCommand(event:ContextMenuEvent):void{trace("paste");} Nota: Ao contrário do conteúdo SWF exibido em um ambiente de navegador, os menus de contexto no AIR não têm nenhum comando incorporado. Sobre menus de contexto em HTML No conteúdo HTML, o evento contextmenu pode ser usado para exibir um menu de contexto. Por padrão, o menu de contexto é exibido automaticamente quando o usuário chama o evento de menu de contexto no texto selecionado (clicando com o botão direito do mouse ou clicando com a tecla Command pressionada no texto). Para evitar que o menu padrão seja aberto, ouça o evento contextmenu e chame o método preventDefault() do objeto de evento: function showContextMenu(event){ event.preventDefault(); } Em seguida, você pode exibir um menu de contexto personalizado usando técnicas DHTML ou exibindo o menu de contexto nativo do AIR. O exemplo a seguir exibe um menu de contexto nativo, chamando o método display() do menu em resposta ao evento contextmenu de HTML: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 94 Trabalho com menus nativos <html> <head> <script src="AIRAliases.js" language="JavaScript" type="text/javascript"></script> <script language="javascript" type="text/javascript"> function showContextMenu(event){ event.preventDefault(); contextMenu.display(window.nativeWindow.stage, event.clientX, event.clientY); } function createContextMenu(){ var menu = new air.NativeMenu(); var command = menu.addItem(new air.NativeMenuItem("Custom command")); command.addEventListener(air.Event.SELECT, onCommand); return menu; } function onCommand(){ air.trace("Context command invoked."); } var contextMenu = createContextMenu(); </script> </head> <body> <p oncontextmenu="showContextMenu(event)" style="-khtml-user-select:auto;">Custom context menu.</p> </body> </html> Definição de forma clara de menus nativos Codificar as propriedades de um menu e de itens de menu pode ser um pouco entediante. No entanto, como os menus têm uma estrutura hierárquica natural, ela é objetiva para gravar uma função que cria um menu usando a definição formatada em XML. A classe a seguir estende o NativeMenu, tomando um objeto XML em seu construtor; para fazer o seguinte apenas: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 95 Trabalho com menus nativos package { import flash.display.NativeMenu; import flash.display.NativeMenuItem; import flash.events.Event; public class DeclarativeMenu extends NativeMenu { public function DeclarativeMenu(XMLMenuDefinition:XML):void { super(); addChildrenToMenu(this, XMLMenuDefinition.children()); } private function addChildrenToMenu(menu:NativeMenu, children:XMLList):NativeMenuItem { var menuItem:NativeMenuItem; var submenu:NativeMenu; for each (var child:XML in children) { if (String(child.@label).length > 0) { menuItem = new NativeMenuItem(child.@label); menuItem.name = child.name(); } else { menuItem = new NativeMenuItem(child.name()); menuItem.name = child.name(); } menu.addItem(menuItem); if (child.children().length() > 0) { menuItem.submenu = new NativeMenu(); addChildrenToMenu(menuItem.submenu,child.children()); } } return menuItem; } } //End class } //End package Para criar um menu com essa classe, passe uma definição de menu XML como a seguinte: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 96 Trabalho com menus nativos var menuDefinition:XML = <root> <FileMenu label='File'> <NewMenu label='New'> <NewTextFile label='Text file'/> <NewFolder label='Folder'/> <NewProject label='Project'/> </NewMenu> <OpenCommand label='Open'/> <SaveCommand label='Save'/> </FileMenu> <EditMenu label='Edit'> <CutCommand label='Cut'/> <CopyCommand label='Copy'/> <PasteCommand label='Paste'/> </EditMenu> <FoodItems label='Food Items'> <Jellyfish/> <Tripe/> <Gizzard/> </FoodItems> </root>; var test:DeclarativeMenu = new DeclarativeMenu(menuDefinition); Para ouvir eventos de menu, você pode ouvir em nível de menu raiz e usar a propriedade event.target.name para detectar que comando foi selecionado. Você também pode pesquisar itens no menu por nome e adicionar ouvintes individuais de evento. Exibição de menus pop-up Você pode exibir qualquer objeto NativeMenu em um tempo e local arbitrários acima de uma janela, chamando o método display() do menu. O método requer uma referência ao palco, portanto, apenas o conteúdo na caixa de proteção do aplicativo pode exibir o menu como pop-up. O método a seguir exibe o menu definido por um objeto NativeMenu chamado popupMenu em resposta a um clique do mouse: private function onMouseClick(event:MouseEvent):void { popupMenu.display(event.target.stage, event.stageX, event.stageY); } Nota: O menu não precisa ser exibido em resposta direta ao evento. Qualquer método pode chamar a função display(). Tratamento de itens de menu O menu despacha eventos quando o usuário o seleciona ou quando seleciona um item de menu. Resumo de eventos de classes de menu Adicione ouvintes de eventos a menus ou itens individuais para tratar eventos de menu. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 97 Trabalho com menus nativos Objeto Eventos despachados NativeMenu NativeMenuEvent.DISPLAYING NativeMenuEvent.SELECT (propagado a partir de itens filhos e submenus) NativeMenuItem NativeMenuEvent.SELECT NativeMenuEvent.DISPLAYING (propagado a partir do menu pai) ContextMenu ContextMenuEvent.MENU_SELECT ContextMenuItem ContextMenuEvent.MENU_ITEM_SELECT NativeMenu.SELECT Eventos de menu Select Para manipular o clique de um item de menu, adicione um ouvinte de evento do evento select ao objeto NativeMenuItem: var menuCommandX:NativeMenuItem = new NativeMenuItem("Command X"); menuCommand.addEventListener(Event.SELECT, doCommandX) Como os eventos select surgem em bolhas para os menus que os contêm, você também pode ouvir eventos select em um menu pai. Ao ouvir no nível de menu, é possível usar a propriedade target do objeto evento para determinar que comando de menu foi selecionado. O exemplo a seguir rastreia o rótulo do comando selecionado: var colorMenuItem:NativeMenuItem = new NativeMenuItem("Choose a color"); var colorMenu:NativeMenu = new NativeMenu(); colorMenuItem.submenu = colorMenu; var red:NativeMenuItem = new NativeMenuItem("Red"); var green:NativeMenuItem = new NativeMenuItem("Green"); var blue:NativeMenuItem = new NativeMenuItem("Blue"); colorMenu.addItem(red); colorMenu.addItem(green); colorMenu.addItem(blue); if(NativeApplication.supportsMenu){ NativeApplication.nativeApplication.menu.addItem(colorMenuItem); NativeApplication.nativeApplication.menu.addEventListener(Event.SELECT, colorChoice); } else if (NativeWindow.supportsMenu){ var windowMenu:NativeMenu = new NativeMenu(); this.stage.nativeWindow.menu = windowMenu; windowMenu.addItem(colorMenuItem); windowMenu.addEventListener(Event.SELECT, colorChoice); } function colorChoice(event:Event):void { var menuItem:NativeMenuItem = event.target as NativeMenuItem; trace(menuItem.label + " has been selected"); } Se você estiver usando a classe ContextMenuItem, poderá ouvir o evento select ou o evento menuItemSelect. O evento menuItemSelect oferece informações adicionais sobre o objeto pertencente ao menu de contexto, mas não surge em bolhas para os menus que os contêm. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 98 Trabalho com menus nativos Exibição de eventos de menu Para manipular a abertura de um menu, você pode adicionar um ouvinte ao evento displaying, que é despachado antes de o menu ser exibido. Você pode usar o evento displaying para atualizar o menu, por exemplo, adicionando ou removendo itens ou atualizando os estados ativados ou marcados de itens individuais. Exemplo: Menu de janela e aplicativo O exemplo a seguir cria o menu mostrado em “Estrutura de menu” na página 87. O menu foi projetado para funcionar no Windows, em que apenas os menus de janela têm suporte, e no Mac OS X, em que apenas menus de aplicativo têm suporte. Para fazer distinção, o construtor de classe MenuExample verifica as propriedades supportsMenu estáticas das classes NativeWindow e NativeApplication. Se NativeWindow.supportsMenu for true, o construtor cria um objeto NativeMenu para a janela e, em seguida, cria e adiciona os submenus File e Edit. Se NativeApplication.supportsMenu for true, o construtor cria e adiciona os menus File e Edit ao menu existente fornecido pelo sistema operacional Mac OS X. O exemplo também ilustra o tratamento de evento de menu. O evento select é manipulado no nível de item e também no nível de menu. Cada menu na cadeia do menu que contém o item selecionado para o menu raiz responde ao evento select. O evento displaying é usado com o menu “Open Recent”. Logo antes de o menu ser aberto, os itens do menu são atualizados da matriz Documentos recentes (que na realidade não é alterada neste exemplo). Embora não demonstrado nesse exemplo, você também pode ouvir eventos displaying em itens individuais. package { import import import import import import import flash.display.NativeMenu; flash.display.NativeMenuItem; flash.display.NativeWindow; flash.display.Sprite; flash.events.Event; flash.filesystem.File; flash.desktop.NativeApplication; public class MenuExample extends Sprite { private var recentDocuments:Array = new Array(new File("app-storage:/GreatGatsby.pdf"), new File("app-storage:/WarAndPeace.pdf"), new File("app-storage:/Iliad.pdf")); public function MenuExample() { var fileMenu:NativeMenuItem; var editMenu:NativeMenuItem; if (NativeWindow.supportsMenu){ stage.nativeWindow.menu = new NativeMenu(); stage.nativeWindow.menu.addEventListener(Event.SELECT, selectCommandMenu); fileMenu = stage.nativeWindow.menu.addItem(new NativeMenuItem("File")); fileMenu.submenu = createFileMenu(); editMenu = stage.nativeWindow.menu.addItem(new NativeMenuItem("Edit")); editMenu.submenu = createEditMenu(); } if (NativeApplication.supportsMenu){ DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 99 Trabalho com menus nativos NativeApplication.nativeApplication.menu.addEventListener(Event.SELECT, selectCommandMenu); fileMenu = NativeApplication.nativeApplication.menu.addItem(new NativeMenuItem("File")); fileMenu.submenu = createFileMenu(); editMenu = NativeApplication.nativeApplication.menu.addItem(new NativeMenuItem("Edit")); editMenu.submenu = createEditMenu(); } } public function createFileMenu():NativeMenu { var fileMenu:NativeMenu = new NativeMenu(); fileMenu.addEventListener(Event.SELECT, selectCommandMenu); var newCommand:NativeMenuItem = fileMenu.addItem(new NativeMenuItem("New")); newCommand.addEventListener(Event.SELECT, selectCommand); var saveCommand:NativeMenuItem = fileMenu.addItem(new NativeMenuItem("Save")); saveCommand.addEventListener(Event.SELECT, selectCommand); var openRecentMenu:NativeMenuItem = fileMenu.addItem(new NativeMenuItem("Open Recent")); openRecentMenu.submenu = new NativeMenu(); openRecentMenu.submenu.addEventListener(Event.DISPLAYING, updateRecentDocumentMenu); openRecentMenu.submenu.addEventListener(Event.SELECT, selectCommandMenu); return fileMenu; } public function createEditMenu():NativeMenu { var editMenu:NativeMenu = new NativeMenu(); editMenu.addEventListener(Event.SELECT, selectCommandMenu); var copyCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Copy")); copyCommand.addEventListener(Event.SELECT, selectCommand); copyCommand.keyEquivalent = "c"; var pasteCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Paste")); pasteCommand.addEventListener(Event.SELECT, selectCommand); pasteCommand.keyEquivalent = "v"; editMenu.addItem(new NativeMenuItem("", true)); var preferencesCommand:NativeMenuItem = editMenu.addItem(new NativeMenuItem("Preferences")); preferencesCommand.addEventListener(Event.SELECT, selectCommand); return editMenu; } private function updateRecentDocumentMenu(event:Event):void { trace("Updating recent document menu."); var docMenu:NativeMenu = NativeMenu(event.target); for each (var item:NativeMenuItem in docMenu.items) { docMenu.removeItem(item); } for each (var file:File in recentDocuments) { DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 100 Trabalho com menus nativos var menuItem:NativeMenuItem = docMenu.addItem(new NativeMenuItem(file.name)); menuItem.data = file; menuItem.addEventListener(Event.SELECT, selectRecentDocument); } } private function selectRecentDocument(event:Event):void { trace("Selected recent document: " + event.target.data.name); } private function selectCommand(event:Event):void { trace("Selected command: " + event.target.label); } private function selectCommandMenu(event:Event):void { if (event.currentTarget.parent != null) { var menuItem:NativeMenuItem = findItemForMenu(NativeMenu(event.currentTarget)); if (menuItem != null) { trace("Select event for \"" + event.target.label + "\" command handled by menu: " + menuItem.label); } } else { trace("Select event for \"" + event.target.label + "\" command handled by root menu."); } } private function findItemForMenu(menu:NativeMenu):NativeMenuItem { for each (var item:NativeMenuItem in menu.parent.items) { if (item != null) { if (item.submenu == menu) { return item; } } } return null; } } } 101 Capítulo 13: Ícones na barra de tarefas Muitos sistemas operacionais têm uma barra de tarefas, como o encaixe do Mac OS X, que pode conter um ícone representando um aplicativo. O Adobe® AIR® oferece uma interface que permite interagir com o ícone na barra de tarefas através da propriedade NativeApplication.nativeApplication.icon. Informações on-line adicionais sobre ícones da barra de tarefas Você encontra mais informações sobre como trabalhar com barras de tarefas nestas fontes: Início rápido (Adobe AIR Developer Connection) • Uso dos ícones da bandeja do sistema e do encaixe Referência de linguagem • DockIcon • SystemTrayIcon Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (procure 'ícones na barra de tarefas do AIR') Sobre ícones na barra de tarefas O AIR cria o objeto NativeApplication.nativeApplication.icon automaticamente. O tipo de objeto é DockIcon ou SystemTrayIcon, dependendo do sistema operacional. É possível determinar qual destas subclasses InteractiveIcon é suportada pelo AIR no sistema operacional atual usando as propriedades NativeApplication.supportsDockIcon e NativeApplication.supportsSystemTrayIcon. A classe base InteractiveIcon oferece as propriedades width, height e bitmaps, que você pode usar para alterar a imagem utilizada para o ícone. No entanto, acessar propriedades específicas de DockIcon ou SystemTrayIcon no sistema operacional incorreto gera um erro de execução. Para definir ou alterar a imagem usada para um ícone, crie uma matriz que contenha uma ou mais imagens e a atribua à propriedade NativeApplication.nativeApplication.icon.bitmaps. O tamanho dos ícones na barra de tarefas pode ser diferente nos diferentes sistemas operacionais. Para evitar a degradação da imagem devido ao dimensionamento, é possível adicionar vários tamanhos de imagem à matriz bitmaps. Se você fornecer mais de uma imagem, o AIR selecionará o tamanho mais próximo do tamanho de exibição atual do ícone na barra de tarefas e só o dimensionará se for necessário. O exemplo abaixo define a imagem para um ícone da barra de tarefas usando duas imagens: NativeApplication.nativeApplication.icon.bitmaps = [bmp16x16.bitmapData, bmp128x128.bitmapData]; Para alterar a imagem de um ícone, atribua uma matriz que contenha a(s) nova(s) imagem(ns) à propriedade bitmaps. Você pode animar o ícone alterando a imagem em resposta a um evento enterFrame ou timer. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 102 Ícones na barra de tarefas Para remover o ícone da área de notificação no Windows e no Linux ou para restaurar a aparência do ícone padrão no Mac OS X, defina bitmaps como uma matriz vazia: NativeApplication.nativeApplication.icon.bitmaps = []; Ícones de encaixe O AIR suporta ícones de encaixe quando NativeApplication.supportsDockIcon é true. A propriedade NativeApplication.nativeApplication.icon representa o ícone do aplicativo no encaixe (não um ícone de encaixe na janela). Nota: O AIR não permite alterar ícones de janela no encaixe do Mac OS X. Além disso, as alterações feitas no ícone de encaixe de aplicativo só são aplicadas enquanto um aplicativo está em execução — o ícone reassume a aparência normal quando o aplicativo é encerrado. Menus com ícone no encaixe É possível adicionar comandos ao menu de encaixe padrão criando um objeto NativeMenu que contenha os comandos e atribuindo o objeto à propriedade NativeApplication.nativeApplication.icon.menu. Os itens do menu são exibidos acima dos itens padrão do menu com ícones no encaixe. Fazer o encaixe pular É possível fazer com que o ícone no encaixe pule chamando o método NativeApplication.nativeApplication.icon.bounce(). Se você definir o parâmetro bounce() priority como informativo, o ícone pulará uma vez. Se você definir o parâmetro como crítico, o ícone pulará até o usuário ativar o aplicativo. As constantes do parâmetro priority são definidas na classe NotificationType. Nota: O ícone não pula se o aplicativo já está ativo. Eventos de ícones no encaixe Quando o usuário clica em um ícone no encaixe, o objeto NativeApplication despacha um evento invoke. Se o aplicativo não estiver em execução, será iniciado pelo sistema. Caso contrário, o evento invoke será entregue à ocorrência do aplicativo em execução. Ícones da bandeja do sistema O AIR oferece suporte a ícones de bandeja do sistema quando NativeApplication.supportsSystemTrayIcon for true, o que no momento só ocorre no Windows e na maioria das distribuições do Linux. No Windows e no Linux, os ícones de bandeja do sistema são exibidos na área de notificação da barra de tarefas. Nenhum ícone é exibido por padrão. Para mostrar um ícone, atribua uma matriz contendo objetos BitmapData à propriedade bitmaps do ícone. Para alterar a imagem do ícone, atribua uma matriz que contenha as novas imagens a bitmaps. Para remover o ícone, defina bitmaps como null. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 103 Ícones na barra de tarefas Menus de ícones da bandeja do sistema É possível adicionar um menu ao ícone da bandeja do sistema criando-se um objeto NativeMenu e o atribuindo à propriedade NativeApplication.nativeApplication.icon.menu (o sistema operacional não oferece um menu padrão). Acesse o menu do ícone da bandeja do sistema clicando no ícone com o botão direito do mouse. Dicas de ferramentas sobre ícones da bandeja do sistema Adicione uma dica de ferramenta a um ícone definindo a propriedade tooltip: NativeApplication.nativeApplication.icon.tooltip = "Application name"; Eventos de ícone da bandeja do sistema O objeto SystemTrayIcon referenciado pela propriedade NativeApplication.nativeApplication.icon despacha um ScreenMouseEvent para eventos click, mouseDown, mouseUp, rightClick, rightMouseDown e rightMouseUp. Você pode usar esses eventos, junto com um menu de ícone, para que os usuários possam interagir com seu aplicativo quando ele não tiver janelas visíveis. Exemplo: Criação de um aplicativo sem janelas O exemplo a seguir cria um aplicativo do AIR que tem um ícone na bandeja do sistema, mas nenhuma janela visível. O ícone na bandeja do sistema tem um menu com um único comando, que permite sair do aplicativo. package { import import import import import import import import import import flash.display.Loader; flash.display.NativeMenu; flash.display.NativeMenuItem; flash.display.NativeWindow; flash.display.Sprite; flash.desktop.DockIcon; flash.desktop.SystemTrayIcon; flash.events.Event; flash.net.URLRequest; flash.desktop.NativeApplication; public class SysTrayApp extends Sprite { public function SysTrayApp():void{ NativeApplication.nativeApplication.autoExit = false; var icon:Loader = new Loader(); var iconMenu:NativeMenu = new NativeMenu(); var exitCommand:NativeMenuItem = iconMenu.addItem(new NativeMenuItem("Exit")); exitCommand.addEventListener(Event.SELECT, function(event:Event):void { NativeApplication.nativeApplication.icon.bitmaps = []; NativeApplication.nativeApplication.exit(); }); if (NativeApplication.supportsSystemTrayIcon) { NativeApplication.nativeApplication.autoExit = false; icon.contentLoaderInfo.addEventListener(Event.COMPLETE, iconLoadComplete); icon.load(new URLRequest("icons/AIRApp_16.png")); var systray:SystemTrayIcon = NativeApplication.nativeApplication.icon as SystemTrayIcon; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 104 Ícones na barra de tarefas systray.tooltip = "AIR application"; systray.menu = iconMenu; } if (NativeApplication.supportsDockIcon){ icon.contentLoaderInfo.addEventListener(Event.COMPLETE,iconLoadComplete); icon.load(new URLRequest("icons/AIRApp_128.png")); var dock:DockIcon = NativeApplication.nativeApplication.icon as DockIcon; dock.menu = iconMenu; } stage.nativeWindow.close(); } private function iconLoadComplete(event:Event):void { NativeApplication.nativeApplication.icon.bitmaps = [event.target.content.bitmapData]; } } } Nota: O exemplo pressupõe que existem arquivos de imagem chamados AIRApp_16.png e AIRApp_128.png em um subdiretório icons do aplicativo. (Arquivos de ícone de exemplo, que você pode copiar para a pasta do seu projeto, são fornecidos no SDK do AIR.) Ícones e botões da barra de tarefas do Windows As representações em forma de ícone de janelas geralmente são exibidas na área de janela de uma barra de tarefas ou de um encaixe, para que os usuários tenham fácil acesso a janelas em segundo plano ou minimizadas. O encaixe do Mac OS X exibe um ícone do seu aplicativo e um ícone de cada janela minimizada. As barras de tarefas do Microsoft Windows e do Linux exibem um botão que contém o ícone do programa e o título de cada janela de tipo normal do seu aplicativo. Realce do botão da janela na barra de ferramentas Quando uma janela está em segundo plano, você pode notificar o usuário de que ocorreu um evento de interesse relacionado à janela. No Mac OS X, você pode notificar o usuário fazendo o ícone de encaixe do aplicativo pular (conforme descrito em “Fazer o encaixe pular” na página 102). No Windows e no Linux, você pode realçar o botão da barra de tarefas da janela chamando o método notifyUser() da ocorrência NativeWindow. O parâmetro type passado para o método determina a urgência da notificação: • NotificationType.CRITICAL: o ícone da janela fica piscando até o usuário colocar a janela no primeiro plano. • NotificationType.INFORMATIONAL: o ícone da janela fica realçado pela troca de cores. Nota: No Linux, só há suporte para o tipo informativo de notificação. Passar um dos valores de tipo para a função notifyUser() criará o mesmo efeito. A seguinte instrução realça o botão da barra de tarefas de uma janela: stage.nativeWindow.notifyUser(NotificationType.CRITICAL); Chamar o método NativeWindow.notifyUser() em um sistema operacional que não dá suporte a notificações de janela não produz qualquer efeito. Use a propriedade NativeWindow.supportsNotification para determinar se a notificação de janela é suportada. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 105 Ícones na barra de tarefas Criação de janelas sem botões ou ícones na barra de tarefas No sistema operacional Windows, as janelas criadas com os tipos utility ou lightweight não aparecem na barra de tarefas. As janelas invisíveis também não. Como a janela inicial é necessariamente do tipo normal, para criar um aplicativo sem nenhuma janela aparecendo na barra de tarefas, você deve fechar a janela inicial ou deixá-la invisível. Para fechar todas as janelas do seu aplicativo sem encerrá-lo, defina a propriedade autoExit do objeto NativeApplication como false antes de fechar a última janela. Para impedir que a janela inicial se torne visível, adicione <visible>false</visible> ao elemento <initalWindow> do arquivo de descrição do aplicativo (e não defina a propriedade visible como true ou chame o método activate() da janela). Nas novas janelas abertas pelo aplicativo, defina a propriedade type do objeto NativeWindowInitOption passado para o construtor de janela como NativeWindowType.UTILITY ou NativeWindowType.LIGHTWEIGHT. No Mac OS X, as janelas minimizadas são exibidas na barra de tarefas do encaixe. Para impedir que o ícone minimizado seja exibido, oculte a janela em vez de minimizá-la. O exemplo a seguir monitora um evento de alteração nativeWindowDisplayState e o cancela se a janela está sendo minimizada. O manipulador define a propriedade visible da janela como false: private function preventMinimize(event:NativeWindowDisplayStateEvent):void{ if(event.afterDisplayState == NativeWindowDisplayState.MINIMIZED){ event.preventDefault(); event.target.visible = false; } } Se uma janela está minimizada no encaixe do Mac OS X quando você define a propriedade visible como false, o ícone no encaixe não é removido. Um usuário ainda poderá clicar no ícone para fazer com que a janela reapareça. 106 Capítulo 14: Trabalho com o sistema de arquivos Você usa as classes fornecidas pela API de sistema de arquivos do Adobe® AIR™ para acessar o sistema de arquivos do computador host. Usando essas classes, você pode acessar e gerenciar diretórios e arquivos, criar diretórios e arquivos, gravar dados em arquivos e assim por diante. Informações adicionais on-line sobre a API de Arquivo AIR Você pode encontrar mais informações sobre o uso de classes API de arquivo nas seguintes fontes: Início rápido (Adobe AIR Developer Connection) • Criação de editor de arquivo de texto Referência de linguagem • Arquivo • FileStream • FileMode Artigos e amostras do Adobe Developer Connection • Conexão de desenvolvedores do Adobe AIR para Flash (pesquisar por 'AIR filesystem') Noções básicas do arquivo AIR O Adobe AIR oferece classes que você pode usar para acessar, criar e gerenciar arquivos e pastas. Essas classes, contidas no pacote flash.filesystem, são usadas da seguinte forma: Classes File Descrição Arquivo O objeto File representa um caminho para um arquivo ou um diretório. Você usa o objeto File para criar um indicador para um arquivo ou pasta, iniciando a interação com o arquivo ou a pasta. FileMode A classe FileMode define constantes de string usadas no parâmetro fileMode dos métodos open() e openAsync() da classe FileStream. O parâmetro fileMode desses métodos determina os recursos disponíveis para o objeto FileStream depois que o arquivo é aberto, o que inclui gravação, leitura, acréscimo e atualização. FileStream O objeto FileStream é usado para abrir arquivos de leitura e gravação. Depois que você criar o objeto File apontando para um arquivo novo ou um já existente, passe esse ponteiro para o objeto FileStream, de modo a poder abrir e, em seguida, manipular dados no arquivo. Alguns métodos na classe File têm versões síncronas e assíncronas: • File.copyTo() e File.copyToAsync() DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 107 Trabalho com o sistema de arquivos • File.deleteDirectory() e File.deleteDirectoryAsync() • File.deleteFile() e File.deleteFileAsync() • File.getDirectoryListing() e File.getDirectoryListingAsync() • File.moveTo() e File.moveToAsync() • File.moveToTrash() e File.moveToTrashAsync() Além disso, as operações FileStream funcionam síncrona ou assincronamente, dependendo de como o objeto FileStream abre o arquivo: chamando o método open() ou o método openAsync(). As versões assíncronas permitem iniciar processos que são executados em segundo plano e despacham eventos quando concluídos (ou quando ocorrerem eventos de erro). Outro código pode ser executado enquanto esses processos de segundo plano assíncronos estão ocorrendo. Nas versões assíncronas das operações, você deve configurar funções do ouvinte de eventos, usando o método addEventListener() do objeto File ou FileStream que chama a função. As versões síncronas permitem escrever códigos mais simples que não se baseiam na configuração de ouvintes de evento. No entanto, como nenhum outro código pode ser executado enquanto o método sincrônico está sendo executado, processos importantes, como processamento e animação de objeto de exibição, podem ser pausados. Trabalho com objetos File O objeto File é um ponteiro para um arquivo ou diretório no sistema de arquivos. A classe File estende a classe FileReference. A classe FileReference, disponível no Adobe® Flash® Player, bem como no AIR, representa um ponteiro para um arquivo, mas a classe File adiciona propriedades e métodos que não são expostos no Flash Player (em um SWF em execução no navegador), devido a considerações sobre segurança. Sobre a classe File Você pode usar a classe File para o seguinte: • Obter o caminho para diretórios especiais, incluindo o diretório do usuário, o diretório de documentos do usuário, o diretório do qual o aplicativo foi iniciado e o diretório de aplicativo. • Cópia de arquivos e diretórios • Movimentação de arquivos e diretórios. • Exclusão de arquivos e diretórios (ou movimentação para a lixeira) • Lista de arquivos e diretórios contidos em um diretório • Criação de arquivos e pastas temporários Depois que o objeto File aponta para um caminho de arquivo, você pode usá-lo para ler e gravar dados de arquivo, usando a classe FileStream. O objeto File pode apontar para o caminho de um arquivo ou diretório que ainda não existe. Você pode usar esse objeto File na criação de arquivos ou diretórios. Caminhos de objetos File Cada objeto File tem duas propriedades que definem cada uma o caminho do objeto: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 108 Trabalho com o sistema de arquivos Propriedade Descrição nativePath Especifica o caminho específico de plataforma para um arquivo. Por exemplo, no Windows o caminho pode ser "c:\Sample directory\test.txt", enquanto no Mac OS pode ser "/Sample directory/test.txt". A propriedade nativePath usa o caractere de barra invertida (\) como o caractere separador de diretório no Windows e o caractere de barra (/) no Mac OS e no Linux. url Ela pode usar o esquema de URL de arquivo para apontar para um arquivo. Por exemplo, no Windows o caminho pode ser "file:///c:/Sample%20directory/teste.txt", enquanto no Mac OS pode ser "file:///Sample%20directory/teste.txt". O tempo de execução inclui outros esquemas especiais de URL além de file e são descritos em “Esquemas URL com suporte” na página 112 A classe File inclui propriedades de indicação de diretórios padrão no Mac OS, no Windows e no Linux. Como apontar um objeto File para um diretório Há maneiras diferentes de configurar o objeto File para apontar para um diretório. Apontar para o diretório inicial do usuário Você pode apontar o objeto File para o diretório inicial do usuário. No Windows, o diretório inicial é o pai do diretório "My Documents" (por exemplo, "C:\Documents and Settings\userName\My Documents"). No Mac OS, é o diretório Users/userName. No Linux, é o diretório /home/userName. O código a seguir configura o objeto File para apontar para o subdiretório AIR Test do diretório inicial: var file:File = File.userDirectory.resolvePath("AIR Test"); Apontar para o diretório documentos do usuário Você pode apontar o objeto File para o diretório documentos do usuário. No Windows, o local padrão é o diretório "My Documents" (por exemplo, "C:\Documents and Settings\userName\My Documents"). No Mac OS, o local padrão é o diretório Users/userName/Documents. No Linux, o local padrão é o diretório /home/userName/Documents. O código a seguir configura o objeto File para apontar para o subdiretório AIR Test do diretório documentos: var file:File = File.documentsDirectory.resolvePath("AIR Test"); Apontar para o diretório da área de trabalho Você pode apontar o objeto File para a área de trabalho. O código a seguir configura o objeto File para apontar para o subdiretório AIR Test da área de trabalho: var file:File = File.desktopDirectory.resolvePath("AIR Test"); Apontar para o diretório de armazenamento do aplicativo Você pode apontar o objeto File para o diretório de armazenamento do aplicativo. Para cada aplicativo AIR, há um caminho associado exclusivo que define o diretório de armazenamento do aplicativo. Esse diretório é exclusivo de cada aplicativo e usuário. Pode ser conveniente usar esse diretório para armazenar dados específicos do usuário e do aplicativo (como dados do usuário ou arquivos de preferências). Por exemplo, o código a seguir aponta o objeto File para um arquivo de preferências, prefs.xml, contido no diretório de armazenamento do aplicativo: var file:File = File.applicationStorageDirectory; file = file.resolvePath("prefs.xml"; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 109 Trabalho com o sistema de arquivos A localização do diretório de armazenamento do aplicativo baseia-se no nome do usuário, na ID do aplicativo e na ID do editor: • No Mac OS, em: /Users/user name/Library/Preferences/applicationID.publisherID/Local Store/ Por exemplo: /Users/babbage/Library/Preferences/com.example.TestApp.02D88EEED35F84C264A183921344EEA353 A629FD.1/Local Store • No Windows: no diretório Documents and Settings, em: user name/Application Data/applicationID.publisherID/Local Store/ Por exemplo: C:\Documents and Settings\babbage\Application Data\com.example.TestApp.02D88EEED35F84C264A183921344EEA353A629FD.1\Local Store • No Linux - In: /home/user name/.appdata/applicationID.publisherID/Local Store/ Por exemplo: /home/babbage/.appdata/com.example.TestApp.02D88EEED35F84C264A183921344EEA353A629FD.1/Loc al Store A URL (e a propriedade url) de um objeto File criado com File.applicationStorageDirectory usa o esquema de URL app-storage (consulte “Esquemas URL com suporte” na página 112), como a seguir: var dir:File = File.applicationStorageDirectory; dir = dir.resolvePath("preferences"); trace(dir.url); // app-storage:/preferences Apontar para o diretório do aplicativo Você pode apontar o objeto File para o diretório em que o aplicativo foi instalado, conhecido como o diretório do aplicativo. Você pode fazer referência a esse diretório, usando a propriedade File.applicationDirectory. Você pode usar esse diretório para examinar o arquivo do descritor do aplicativo ou outros recursos instalados com o aplicativo. Por exemplo, o código a seguir aponta o objeto File para um diretório chamado images no diretório do aplicativo: var dir:File = File.applicationDirectory; dir = dir.resolvePath("images"); A URL (e propriedade url) de um objeto File criado com File.applicationDirectory usa o esquema de URL app (consulte “Esquemas URL com suporte” na página 112), como a seguir: var dir:File = File.applicationDirectory; dir = dir.resolvePath("images"); trace(dir.url); // app:/images Apontar para a raiz filesystem O método File.getRootDirectories() lista todos os volumes de raiz, como C: e volumes montados em um computador Windows. No Mac OS e no Linux, esse método sempre retorna o diretório raiz exclusivo do computador (o diretório "/"). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 110 Trabalho com o sistema de arquivos Como apontar para um diretório explícito Você pode apontar o objeto File para um diretório explícito, definindo a propriedade nativePath do objeto File, conforme o seguinte exemplo (no Windows): var file:File = new File(); file.nativePath = "C:\\AIR Test\"; Navegação para caminhos relativos Você pode usar o método resolvePath() para obter um caminho relativo a outro caminho determinado. Por exemplo, o código a seguir configura o objeto File para apontar para o subdiretório "AIR Test" do diretório inicial do usuário: var file:File = File.userDirectory; file = file.resolvePath("AIR Test"); Você também pode usar a propriedade url do objeto File para apontar para um diretório com base em uma seqüência de URL, conforme segue: var urlStr:String = "file:///C:/AIR Test/"; var file:File = new File() file.url = urlStr; Para obter mais informações, consulte “Modificação de caminhos do File” na página 112. Permissão para que o usuário navegue para selecionar um diretório A classe File inclui o método browseForDirectory(), que apresenta uma caixa de diálogo de sistema na qual o usuário pode selecionar um diretório para atribuir ao objeto. O método browseForDirectory() é assíncrono. Ele despacha um evento select se o usuário selecionar um diretório e clicar no botão Abrir, ou despacha um evento cancel se o usuário clicar no botão Cancelar. Por exemplo, o código a seguir permite que o usuário selecione um diretório e fornece o caminho do diretório na seleção: var file:File = new File(); file.addEventListener(Event.SELECT, dirSelected); file.browseForDirectory("Select a directory"); function dirSelected(e:Event):void { trace(file.nativePath); } Como apontar para o diretório do qual o aplicativo foi chamado Você pode obter a localização do diretório do qual o aplicativo foi chamado, marcando a propriedade currentDirectory do objeto InvokeEvent despachada quando o aplicativo é chamado. Para obter detalhes, consulte“Captura de argumentos de linha de comando” na página 292. Como apontar um objeto File para um arquivo Há maneiras diferentes de definir o arquivo para o qual o objeto File aponta. Apontar para um caminho de arquivo explícito Você pode usar o método resolvePath() para obter um caminho relativo a outro caminho determinado. Por exemplo, o código a seguir define que o objeto File aponte para o arquivo log.txt no diretório de armazenamento do aplicativo: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 111 Trabalho com o sistema de arquivos var file:File = File.applicationStorageDirectory; file = file.resolvePath("log.txt"); Você pode usar a propriedade url do objeto File para apontá-lo para um arquivo ou diretório com base em uma seqüência de URL, conforme segue: var urlStr:String = "file:///C:/AIR Test/test.txt"; var file:File = new File() file.url = urlStr; Você também pode passar a URL para a função de construtor File(), como no seguinte: var urlStr:String = "file:///C:/AIR Test/test.txt"; var file:File = new File(urlStr); A propriedade url sempre retorna a versão codificada de URI da URL (por exemplo, espaços em branco são substituídos por "%20): file.url = "file:///c:/AIR Test"; trace(file.url); // file:///c:/AIR%20Test Você também pode usar a propriedade nativePath do objeto File para definir um caminho explícito. Por exemplo, o código a seguir, quando executado em um computador com o Windows, define um objeto File para o arquivo test.txt no subdiretório AIR Test da unidade C: var file:File = new File(); file.nativePath = "C:/AIR Test/test.txt"; Você também pode passar esse caminho para a função de construtor File(), como no seguinte: var file:File = new File("C:/AIR Test/test.txt"); No Windows, você pode usar o caractere barra (/) ou barra invertida (\) como o delimitador de caminho da propriedade nativePath. No Mac OS e no Linux, use o caractere barra (/) como o delimitador de caminho para o nativePath: var file:File = new File(/Users/dijkstra/AIR Test/test.txt"); Para obter mais informações, consulte “Modificação de caminhos do File” na página 112. Enumeração de arquivos em um diretório Você pode usar o método getDirectoryListing() do objeto File para obter uma matriz de objetos File apontando para arquivos e subdiretórios no nível raiz de um diretório. Para obter mais informações, consulte “Enumeração de diretórios” na página 117. Permissão para que o usuário navegue para selecionar um arquivo A classe File inclui os seguintes métodos que apresentam uma caixa de diálogo de sistema na qual o usuário pode selecionar um arquivo para atribuir ao objeto: • browseForOpen() • browseForSave() • browseForOpenMultiple() DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 112 Trabalho com o sistema de arquivos Cada um desses métodos é assíncrono. Os métodos browseForOpen() e browseForSave() despacham o evento select quando o usuário seleciona um arquivo (ou caminho de destino, no caso de browseForSave()). Com os métodos browseForOpen() e browseForSave(), na seleção, o objeto File de destino aponta para os arquivos selecionados. O método browseForOpenMultiple() despacha um evento selectMultiple quando o usuário seleciona arquivos. O evento selectMultiple é do tipo FileListEvent, que tem a propriedade files, que é uma matriz de objetos File (apontando para os arquivos selecionados). Por exemplo, o código a seguir apresenta para o usuário a caixa de diálogo "Abrir", na qual é possível selecionar um arquivo: var fileToOpen:File = File.documentsDirectory; selectTextFile(fileToOpen); function selectTextFile(root:File):void { var txtFilter:FileFilter = new FileFilter("Text", "*.as;*.css;*.html;*.txt;*.xml"); root.browseForOpen("Open", [txtFilter]); root.addEventListener(Event.SELECT, fileSelected); } function fileSelected(event:Event):void { trace(fileToOpen.nativePath); } Se o aplicativo tiver outra caixa de diálogo de navegação aberta quando você chamar o método de navegação, o tempo de execução emitirá uma exceção Erro. Modificação de caminhos do File Você também pode modificar o caminho de um objeto File existente, chamando o método resolvePath() ou modificando a propriedade nativePath ou url do objeto, conforme nos exemplos a seguir (no Windows): var file1:File = File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); trace(file1.nativePath); // C:\Documents and Settings\userName\My Documents\AIR Test var file2:File = File.documentsDirectory; file2 = file2.resolvePath(".."); trace(file2.nativePath); // C:\Documents and Settings\userName var file3:File = File.documentsDirectory; file3.nativePath += "/subdirectory"; trace(file3.nativePath); // C:\Documents and Settings\userName\My Documents\subdirectory var file4:File = new File(); file4.url = "file:///c:/AIR Test/test.txt"; trace(file4.nativePath); // C:\AIR Test\test.txt Ao usar a propriedade nativePath, você usa o caractere de barra (/) ou barra invertida (\) como o caractere separador de diretório no Windows; no Mac OS e no Linux, você usa o caractere de barra (/). No Windows, lembre-se de digitar o caractere de barra invertida duas vezes em uma literal de string. Esquemas URL com suporte Você pode usar qualquer um dos seguintes esquemas URL na definição da propriedade url de um objeto File: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 113 Trabalho com o sistema de arquivos esquema URL Descrição file Use para especificar um caminho relativo à raiz do sistema de arquivos. Por exemplo: file:///c:/AIR Test/test.txt A URL padrão especifica se a URL de arquivo usa a forma file://<host>/<path>. Como um caso especial, <host> pode ser a string vazia, que é interpretada como "a máquina a partir da qual a URL está sendo interpretada." Por essa razão, as URLs de arquivo normalmente têm três barras (///). app Use para especificar um caminho relativo ao diretório raiz do aplicativo instalado (o diretório que contém o arquivo application.xml do aplicativo instalado). Por exemplo, o caminho a seguir aponta para um subdiretório de imagens do diretório do aplicativo instalado: app:/images app-storage Use para especificar um caminho relativo ao diretório de armazenamento do aplicativo. Para cada aplicativo instalado, o AIR define um diretório exclusivo de armazenamento do aplicativo, que é um local útil para armazenar dados específicos desse aplicativo. Por exemplo, o caminho a seguir aponta para o arquivo prefs.xml em um subdiretório de configurações do diretório de armazenamento do aplicativo: app-storage:/settings/prefs.xml Localização do caminho relativo entre dois arquivos Você pode usar o método getRelativePath() para localizar o caminho relativo entre dois arquivos: var file1:File = File.documentsDirectory.resolvePath("AIR Test"); var file2:File = File.documentsDirectory file2 = file2.resolvePath("AIR Test/bob/test.txt"); trace(file1.getRelativePath(file2)); // bob/test.txt O segundo parâmetro do método getRelativePath(), o parâmetro useDotDot, permite que a sintaxe .... seja retornada nos resultados, para indicar diretórios pai: var file1:File = File.documentsDirectory; file1 = file1.resolvePath("AIR Test"); var file2:File = File.documentsDirectory; file2 = file2.resolvePath("AIR Test/bob/test.txt"); var file3:File = File.documentsDirectory; file3 = file3.resolvePath("AIR Test/susan/test.txt"); trace(file2.getRelativePath(file1, true)); // ../.. trace(file3.getRelativePath(file2, true)); // ../../bob/test.txt Obtenção de versões canônicas de nomes de arquivo No Windows e no Mac OS, os nomes e caminhos de arquivo não fazem distinção entre letras maiúsculas e minúsculas. No exemplo a seguir, dois objetos File apontam para o mesmo arquivo: File.documentsDirectory.resolvePath("test.txt"); File.documentsDirectory.resolvePath("TeSt.TxT"); No entanto, nomes de documentos e de diretórios incluem o uso de maiúsculas e minúsculas. Por exemplo, o seguinte assume que há uma pasta com nome AIR Test no diretório de documentos, como nos exemplos a seguir: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 114 Trabalho com o sistema de arquivos var file:File = File.documentsDirectory.resolvePath("AIR test"); trace(file.nativePath); // ... AIR test file.canonicalize(); trace(file.nativePath); // ... AIR Test O método canonicalize() converte o objeto nativePath para usar maiúsculas e minúsculas corretas para o nome de arquivo ou de diretório. Em sistemas de arquivo que fazem distinção entre maiúsculas e minúsculas (como Linux), quando vários arquivos possuem nomes cuja distinção é somente a letra maiúscula ou minúscula, o método canonicalize() ajusta o caminho para que corresponda ao primeiro arquivo encontrado (em uma ordem determinada pelo sistema de arquivos) Você também pode usar o método canonicalize() para converter nomes de arquivos pequenos (nomes "8,3") em nomes de arquivos longos do Windows, como nos exemplos seguintes: var path:File = new File(); path.nativePath = "C:\\AIR~1"; path.canonicalize(); trace(path.nativePath); // C:\AIR Test Trabalho com pacotes e links simbólicos Vários sistemas operacionais oferecem suporte a arquivos de pacote e arquivos de link simbólico: Pacotes – No Mac OS, os diretórios podem ser designados como pacotes e mostrados no Finder do Mac OS como um arquivo único, em vez de um diretório. Links simbólicos — O Mac OS, o Linux e o Windows Vista oferecem suporte a links simbólicos. Os links simbólicos permitem que um arquivo aponte para outro arquivo ou diretório no disco. Embora semelhantes, os links simbólicos não são o mesmo que alias. O alias é sempre reportado como arquivo (em vez de diretório), e ler ou gravar em um alias ou atalho nunca afeta o diretório ou arquivo original para o qual ele aponta. Por outro lado, o link simbólico se comporta exatamente como o arquivo ou diretório para o qual aponta. Ele pode ser reportado como um arquivo ou diretório, e ler ou gravar em um link simbólico afetará o arquivo ou diretório para o qual ele aponta, não o link simbólico propriamente dito. Além disso, no Windows, a propriedade isSymbolicLink de um objeto File que faça referência a um ponto de junção (usado no sistema de arquivos NTFS) é definida como true. A classe File inclui as propriedades isPackage e isSymbolicLink para verificar se o objeto File faz referência a um pacote ou link simbólico. O código a seguir percorre o diretório da área de trabalho do usuário, listando subdiretórios que não sejam pacotes: var desktopNodes:File = File.desktopDirectory.getDirectoryListing(); for (var i:uint = 0; i < desktopNodes.length; i++) { if (desktopNodes[i].isDirectory && !!desktopNodes[i].isPackage) { trace(desktopNodes[i].name); } } O código a seguir percorre o diretório da área de trabalho do usuário, listando arquivos e diretórios que não sejam links simbólicos: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 115 Trabalho com o sistema de arquivos var desktopNodes:File = File.desktopDirectory.getDirectoryListing(); for (var i:uint = 0; i < desktopNodes.length; i++) { if (!desktopNodes[i].isSymbolicLink) { trace(desktopNodes[i].name); } } O método canonicalize() altera o caminho do link simbólico para apontar para o arquivo ou diretório ao qual o link se refere. O código a seguir percorre o diretório da área de trabalho do usuário e relata os caminhos referenciados pelos arquivos que sejam links simbólicos: var desktopNodes:File = File.desktopDirectory.getDirectoryListing(); for (var i:uint = 0; i < desktopNodes.length; i++) { if (desktopNodes[i].isSymbolicLink) { var linkNode:File = desktopNodes[i] as File; linkNode.canonicalize(); trace(linkNode.nativePath); } } Determinação de espaço disponível em um volume A propriedade spaceAvailable do objeto File é o espaço disponível para uso no local do File, em bytes. Por exemplo, o código a seguir verifica o espaço disponível no diretório de armazenamento do aplicativo: trace(File.applicationStorageDirectory.spaceAvailable); Se o objeto File fizer referência a um diretório, a propriedade spaceAvailable indicará o espaço no diretório que os arquivos podem usar. Se o objeto File fizer referência a um arquivo, a propriedade spaceAvailable indicará o espaço no qual o arquivo poderá crescer. Se o local do arquivo não existir, a propriedade spaceAvailable será definida como 0. Se o objeto File fizer referência a um link simbólico, a propriedade spaceAvailable será definida como espaço disponível no local para o qual o link simbólico aponta. Geralmente o espaço disponível para um diretório ou arquivo é igual ao espaço disponível no volume que contém o diretório ou o arquivo. No entanto, o espaço disponível pode levar em conta limites por cotas e por diretório. A adição de um arquivo ou diretório a um volume geralmente requer mais espaço que o tamanho real do arquivo ou o tamanho do conteúdo do diretório. Por exemplo, o sistema operacional pode exigir mais espaço para armazenar informações sobre índice. Ou os setores de disco necessários podem usar espaço adicional. Além disso, o espaço disponível muda dinamicamente. Dessa forma, você não poderá alocar todo o espaço informado para o armazenamento de arquivos. Para obter informações sobre como gravar no sistema de arquivos, consulte“Leitura e gravação de arquivos” na página 121. Obtenção de informações sobre o sistema de arquivos A classe File inclui as seguintes propriedades estáticas que apresentam algumas informações úteis sobre o sistema de arquivos: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 116 Trabalho com o sistema de arquivos Propriedade Descrição File.lineEnding A seqüência de caracteres de final de linha usada pelo sistema operacional de hospedagem. No Mac OS e no Linux, ele é o caractere de alimentação de linha. No Windows, esse é o caractere de retorno de carro seguido pelo caractere de alimentação de linha. File.separator O caractere separador de componente do caminho do sistema operacional de hospedagem. No Mac OS e no Linux, ele é o caractere de barra (/). No Windows, ele é o caractere de barra invertida (\). File.systemCharset A codificação padrão usada em arquivos pelo sistema operacional de hospedagem. Ela pertence ao conjunto de caracteres usado pelo sistema operacional, correspondente ao respectivo idioma. A classe Capabilities também inclui informações úteis sobre o sistema, que podem ser valiosas ao trabalhar com arquivos: Propriedade Descrição Capabilities.hasIME Especifica se o player está sendo executado em um sistema que possui (true) ou não possui (false) um IME (editor de métodos de entrada) instalado. Capabilities.language Especifica o código de idioma do sistema no qual o player está sendo executado. Capabilities.os Especifica o sistema operacional atual. Trabalho com diretórios O tempo de execução oferece a você recursos para trabalhar com diretórios no sistema de arquivos local. Para obter detalhes sobre a criação de objetos File que apontam para diretórios, consulte “Como apontar um objeto File para um diretório” na página 108. Criação de diretórios O método File.createDirectory() permite criar um diretório. Por exemplo, o código a seguir cria um diretório com nome AIR Test como um subdiretório do diretório inicial do usuário: var dir:File = File.userDirectory.resolvePath("AIR Test"); dir.createDirectory(); Se o diretório existir, o método createDirectory() não faz nada. Além disso, em alguns modos, o objeto FileStream cria diretórios ao abrir arquivos. Diretórios ausentes são criados quando você cria uma ocorrência FileStream com o parâmetro fileMode do construtor FileStream() definido como FileMode.APPEND ou FileMode.WRITE. Para obter mais informações, consulte “Fluxo de trabalho de leitura e gravação de arquivos” na página 121. Criação de diretório temporário A classe File inclui o método createTempDirectory(), que cria um diretório na pasta de diretórios temporários do Sistema, como no exemplo a seguir: var temp:File = File.createTempDirectory(); O método createTempDirectory() cria automaticamente um diretório temporário exclusivo (poupando o seu trabalho de determinar um novo local exclusivo). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 117 Trabalho com o sistema de arquivos Você pode usar um diretório temporário para armazenar temporariamente arquivos temporários usados em uma sessão do aplicativo. Observe que há um método createTempFile() para criar arquivos temporários novos e exclusivos no diretório temporário System. Pode ser conveniente excluir o diretório temporário antes de fechar o aplicativo, uma vez que ele não é excluído automaticamente. Enumeração de diretórios Você pode usar o método getDirectoryListing() ou o método getDirectoryListingAsync() do objeto File para obter uma matriz de objetos File apontando para arquivos e subpastas em um diretório. Por exemplo, o código a seguir lista o conteúdo do diretório de documentos do usuário (sem examinar subdiretórios): var directory:File = File.documentsDirectory; var contents:Array = directory.getDirectoryListing(); for (var i:uint = 0; i < contents.length; i++) { trace(contents[i].name, contents[i].size); } Ao usar a versão assíncrona do método, o objeto de evento directoryListing terá a propriedade files que é a matriz de objetos File pertencentes aos diretórios: var directory:File = File.documentsDirectory; directory.getDirectoryListingAsync(); directory.addEventListener(FileListEvent.DIRECTORY_LISTING, dirListHandler); function dirListHandler(event:FileListEvent):void { var contents:Array = event.files; for (var i:uint = 0; i < contents.length; i++) { trace(contents[i].name, contents[i].size); } } Cópia e movimentação de diretórios Você pode copiar ou mover o diretório, usando os mesmos métodos utilizados para copiar ou mover um arquivo. Por exemplo, o código a seguir copia um diretório de forma síncrona: var sourceDir:File = File.documentsDirectory.resolvePath("AIR Test"); var resultDir:File = File.documentsDirectory.resolvePath("AIR Test Copy"); sourceDir.copyTo(resultDir); Quando você especifica true para o parâmetro overwrite do método copyTo(), todos arquivos e pastas em um diretório de destino existente são excluídos e substituídos pelos arquivos e pastas no diretório de origem (mesmo se o arquivo de destino não existir no diretório de origem). O diretório especificado como o parâmetro newLocation do método copyTo() especifica o caminho para o diretório resultante; ele não especifica o diretório pai que conterá o diretório resultante. Para obter detalhes, consulte “Cópia e movimentação de arquivos” na página 119. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 118 Trabalho com o sistema de arquivos Exclusão de conteúdo do diretório A classe File inclui os métodos deleteDirectory() e deleteDirectoryAsync(). Esses métodos excluem diretórios; o primeiro trabalha de forma síncrona, o segundo trabalha de forma assíncrona (consulte “Noções básicas do arquivo AIR” na página 106). Os dois métodos incluem o parâmetro deleteDirectoryContents (com um valor Booleano); quando esse parâmetro estiver definido como true (o valor padrão será false) a chamada do método excluirá diretórios não vazios; caso contrário, apenas diretórios vazios serão excluídos. Por exemplo, o código a seguir exclui de modo síncrono o subdiretório AIR Test do diretório de documentos do usuários: var directory:File = File.documentsDirectory.resolvePath("AIR Test"); directory.deleteDirectory(true); O código a seguir exclui de modo assíncrono o subdiretório AIR Test do diretório de documentos do usuário: var directory:File = File.documentsDirectory.resolvePath("AIR Test"); directory.addEventListener(Event.COMPLETE, completeHandler) directory.deleteDirectoryAsync(true); function completeHandler(event:Event):void { trace("Deleted.") } Também estão incluídos os métodos moveToTrash() e moveToTrashAsync(), que você pode usar para mover um diretório para a lixeira do Sistema. Para obter detalhes, consulte “Movimentação de arquivo para a lixeira” na página 120. Trabalho com arquivos Usando a API de arquivo AIR, você pode adicionar recursos básicos de interação de arquivo a seus aplicativos. Por exemplo, você pode ler e gravar arquivos, copiar e excluir arquivos e assim por diante. Como seus aplicativos podem acessar o sistema de arquivos local, consulte “Segurança do AIR” na página 23, se ainda não tiver feito isso. Nota: Você pode associar um tipo de arquivo a um aplicativo AIR (de modo que, quando você clicar nele duas vezes, o aplicativo seja aberto). Para obter detalhes, consulte “Gerenciamento de associações de arquivos” na página 299. Obtenção de informações de arquivos A classe File inclui as seguintes propriedades que oferecem informações sobre um arquivo ou diretório para o qual o objeto File aponta: Propriedade File Descrição creationDate A data de criação do arquivo no disco local. creator Obsoleto — usa a propriedade extension. (Essa propriedade relata o tipo de criador Macintosh do arquivo, usado somente nas versões do Mac OS anteriores ao Mac OS X). exists Se o arquivo ou diretório referenciado existir. extension A extensão de arquivo, que é a parte seguinte ao nome (e não incluindo) o ponto final ("."). Se não houver ponto no nome do arquivo, a extensão será null. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 119 Trabalho com o sistema de arquivos Propriedade File Descrição icon Um objeto Icon que contém os ícones definidos para o arquivo. isDirectory Se a referência do objeto File for a um diretório. modificationDate A data da última modificação do arquivo ou diretório no disco local. name O nome do arquivo ou diretório (incluindo a extensão de arquivo, se houver) no disco local. nativePath O caminho completo na representação do sistema operacional de hospedagem. Consulte “Caminhos de objetos File” na página 107. parent A pasta que contém a pasta ou o arquivo representado pelo objeto File. Essa propriedade será null se o objeto File fizer referência a um arquivo ou diretório na raiz do sistema de arquivos. size O tamanho do arquivo no disco local, em bytes. type Obsoleto — usa a propriedade extension. (No Macintosh, essa propriedade é o tipo de arquivo com quatro caracteres, usado somente nas versões do Mac OS anteriores ao Mac OS X). url A URL do arquivo ou diretório. Consulte “Caminhos de objetos File” na página 107. Para obter detalhes sobre essas propriedades, consulte a entrada da classe File na Referência de Componentes e Linguagem do ActionScript 3.0 (http://www.adobe.com/go/learn_air_aslr_br). Cópia e movimentação de arquivos A classe File inclui dois métodos de cópia de arquivos ou diretórios: copyTo() e copyToAsync(). A classe File inclui dois métodos para mover arquivos ou diretórios: moveTo() e moveToAsync(). Os métodos copyTo() e moveTo() funcionam de modo síncrono e os métodos copyToAsync() e moveToAsync() funcionam de modo assíncrono (consulte “Noções básicas do arquivo AIR” na página 106). Para copiar ou mover um arquivo, defina dois objetos File. Um aponta para o arquivo que deve ser copiado ou movido, e é o objeto que chama o método de cópia ou movimentação; o outro aponta para o caminho de destino (resultado). O seguinte copia o arquivo test.txt do subdiretório AIR Test do diretório de documentos do usuário em um arquivo com nome copy.txt no mesmo diretório: var original:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var newFile:File = File.resolvePath("AIR Test/copy.txt"); original.copyTo(newFile, true); Nesse exemplo, o valor do parâmetro overwrite do método copyTo() (o segundo parâmetro) é definido como true. Definindo-o como true, o arquivo de destino existente é sobrescrito. Esse parâmetro é opcional. Se você defini-lo como false (o valor padrão), a operação despacha um evento IOErrorEvent se o arquivo de destino existir (e o arquivo não é copiado). As versões “Async” dos métodos de cópia e movimentação funcionam de modo assíncrono. Use o método addEventListener() para monitorar a conclusão da tarefa ou as condições de erro, como no código a seguir: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 120 Trabalho com o sistema de arquivos var original = File.documentsDirectory; original = original.resolvePath("AIR Test/test.txt"); var destination:File = File.documentsDirectory; destination = destination.resolvePath("AIR Test 2/copy.txt"); original.addEventListener(Event.COMPLETE, fileMoveCompleteHandler); original.addEventListener(IOErrorEvent.IO_ERROR, fileMoveIOErrorEventHandler); original.moveToAsync(destination); function fileMoveCompleteHandler(event:Event):void { trace(event.target); // [object File] } function fileMoveIOErrorEventHandler(event:IOErrorEvent):void { trace("I/O Error."); } A classe File também inclui os métodos File.moveToTrash() e File.moveToTrashAsync(), que movem o arquivo ou diretório para a lixeira do sistema. Exclusão de arquivo A classe File inclui os métodos deleteFile() e deleteFileAsync(). Esses métodos excluem arquivos; o primeiro trabalha de forma síncrona, o segundo trabalha de forma assíncrona (consulte “Noções básicas do arquivo AIR” na página 106). Por exemplo, o código a seguir exclui de modo síncrono o arquivo test.txt do diretório de documentos do usuário: var file:File = File.documentsDirectory.resolvePath("test.txt"); file.deleteFile(); O código a seguir exclui de modo assíncrono o arquivo test.txt do diretório de documentos do usuário: var file:File = File.documentsDirectory.resolvePath("test.txt"); file.addEventListener(Event.COMPLETE, completeHandler) file.deleteFileAsync(); function completeHandler(event:Event):void { trace("Deleted.") } Também estão incluídos os métodos moveToTrash() e moveToTrashAsync(), que você pode usar para mover um arquivo ou diretório para a lixeira do Sistema. Para obter detalhes, consulte “Movimentação de arquivo para a lixeira” na página 120. Movimentação de arquivo para a lixeira A classe File inclui os métodos moveToTrash() e moveToTrashAsync(). Esses métodos enviam um arquivo ou diretório para a lixeira do Sistema; o primeiro trabalha de forma síncrona, o segundo trabalha de forma assíncrona (consulte “Noções básicas do arquivo AIR” na página 106). Por exemplo, o código a seguir move de modo síncrono o arquivo test.txt no diretório de documentos do usuários para a lixeira do Sistema: var file:File = File.documentsDirectory.resolvePath("test.txt"); file.moveToTrash(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 121 Trabalho com o sistema de arquivos Criação de arquivo temporário A classe File inclui o método createTempFile(), que cria um arquivo na pasta de diretórios temporários do Sistema, como no exemplo a seguir: var temp:File = File.createTempFile(); O método createTempFile() cria automaticamente um arquivo temporário exclusivo (poupando o seu trabalho de determinar um novo local exclusivo). Você pode usar um arquivo temporário para armazenar temporariamente informações usadas em uma sessão do aplicativo. Observe que também há o método createTempDirectory() para criar um diretório temporário exclusivo no diretório temporário System. Pode ser conveniente excluir o arquivo temporário antes de fechar o aplicativo, uma vez que ele não é excluído automaticamente. Leitura e gravação de arquivos A classe FileStream permite que aplicativos AIR leiam e gravem no sistema de arquivos. Fluxo de trabalho de leitura e gravação de arquivos O fluxo de trabalho de leitura e gravação de arquivos é o seguinte. Inicializa o objeto File que aponta para o caminho. Esse é o caminho do arquivo com que você deseja trabalhar (ou um arquivo que você criará mais tarde). var file:File = File.documentsDirectory; file = file.resolvePath("AIR Test/testFile.txt"); Este exemplo usa a propriedade File.documentsDirectory e o método resolvePath() do objeto File para inicializá-lo. No entanto, há várias outras maneiras de apontar o objeto File para um arquivo. Para obter mais informações, consulte “Como apontar um objeto File para um arquivo” na página 110. Inicializa o objeto FileStream. Chama o método open() ou openAsync() do objeto FileStream. O método que você chama depende de você desejar abrir o arquivo para operações síncronas ou assíncronas. Use o objeto File como parâmetro file do método open. No parâmetro fileMode, especifique uma constante da classe FileMode que determine o modo como você usará o arquivo. Por exemplo, o código a seguir inicializa o objeto FileStream que é usado para criar um arquivo e substituir algum dado existente: var fileStream:FileStream = new FileStream(); fileStream.open(file, FileMode.WRITE); Para obter mais informações, consulte“Inicialização de objeto FileStream e abertura e fechamento de arquivos” na página 123, e “modos de abertura FileStream” na página 122. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 122 Trabalho com o sistema de arquivos Se você abriu o arquivo de modo assíncrono (usando o método openAsync()), adicione e configure ouvintes de eventos para o objeto FileStream. Esses métodos de ouvintes de eventos respondem aos eventos despachados pelo objeto FileStream em uma variedade de situações, como quando os dados são lidos do arquivo, quando são encontrados erros E/S ou quando a quantidade completa de dados para gravação tiver sido gravada. Para obter detalhes, consulte “Programação assíncrona e eventos gerados por um objeto FileStream aberto assincronicamente” na página 127. Incluir código de leitura e gravação de dados, conforme necessário. Há vários métodos da classe FileStream relacionados a leitura e gravação. (Cada um deles inicia com "read" ou "write"). O método escolhido para ser usado na leitura ou gravação de dados depende do formato de dados no arquivo de destino. Por exemplo, se os dados no arquivo de destino forem texto de codificação UTF, você pode usar os métodos readUTFBytes() e writeUTFBytes(). Se desejar tratar os dados como matrizes de bytes, você pode usar os métodos readByte(), readBytes(), writeByte() e writeBytes(). Para saber detalhes, consulte “Formatos de dados e seleção de métodos de leitura e gravação para uso” na página 128. Se você abriu o arquivo de modo assíncrono, certifique-se de que há dados suficientes disponíveis antes de chamar o método de leitura. Para obter detalhes, consulte “O buffer de leitura e a propriedade bytesAvailable do objeto FileStream” na página 125. Antes de fazer a gravação em um arquivo, se desejar verificar a quantidade de espaço em disco disponível, você poderá assinalar a propriedade spaceAvailable do objeto File. Para obter mais informações, consulte “Determinação de espaço disponível em um volume” na página 115. Chama o método close() do objeto FileStream quando você tiver terminado o trabalho no arquivo. Isso torna o arquivo disponível para outros aplicativos. Para obter detalhes, consulte “Inicialização de objeto FileStream e abertura e fechamento de arquivos” na página 123. Para visualizar um aplicativo de amostra que usa a classe FileStream para ler e gravar arquivos, consulte os seguintes artigos no Centro de desenvolvimento do Adobe AIR: • Criação de editor de arquivo de texto Trabalho com objetos FileStream A classe FileStream define métodos de abertura, leitura e gravação de arquivos. modos de abertura FileStream Cada um dos métodos open() e openAsync() do objeto FileStream inclui o parâmetro fileMode, que define algumas propriedades de um fluxo de arquivo, incluindo o seguinte: • A capacidade de ler do arquivo • A capacidade de gravar no arquivo • Se os dados serão sempre acrescentados ao final do arquivo (durante a gravação). • O que fazer quando o arquivo não existir (e quando os respectivos diretórios pai não existirem) A seguir, os vários modos de arquivo (que você pode especificar como o parâmetro fileMode dos métodos open() e openAsync()): DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 123 Trabalho com o sistema de arquivos modo File Descrição FileMode.READ Especifica que o arquivo está aberto somente para leitura. FileMode.WRITE Especifica que o arquivo está aberto para gravação. Se o arquivo não existir, ele é criado quando o objeto FileStream é aberto. Se o arquivo existir, todos os dados existentes são excluídos. FileMode.APPEND Especifica que o arquivo está aberto para acréscimo. O arquivo é criado se ele não existir. Se o arquivo existir, os dados existentes não são substituídos e todas as gravações serão iniciadas no final do arquivo. FileMode.UPDATE Especifica que o arquivo está aberto para leitura e gravação. Se o arquivo não existir, ele é criado. Especifique esse modo para acesso de leitura/gravação aleatório ao arquivo. Você pode ler a partir de qualquer posição no arquivo e, ao gravar no arquivo, apenas os bytes gravados substituirão os bytes existentes (todos os demais bytes permanecerão inalterados). Inicialização de objeto FileStream e abertura e fechamento de arquivos Ao abrir o objeto FileStream, você o torna disponível para a leitura e gravação de dados em um arquivo. Você abre o objeto FileStream passando o objeto File para o método open() ou openAsync() do objeto FileStream: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.READ); O parâmetro fileMode (o segundo parâmetro dos métodos open() e openAsync()) especifica o modo em que o arquivo deve ser aberto: para leitura, gravação, acréscimo ou atualização. Para obter detalhes, consulte a seção anterior,“modos de abertura FileStream” na página 122. Se você usar o método openAsync() para abrir o arquivo para operações de arquivo de modo assíncrono, configure os ouvintes de eventos para tratar os eventos assíncronos: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completeHandler); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(IOErrorEvent.IOError, errorHandler); myFileStream.open(myFile, FileMode.READ); function completeHandler(event:Event):void { // ... } function progressHandler(event:ProgressEvent):void { // ... } function errorHandler(event:IOErrorEvent):void { // ... } O arquivo é aberto para operações síncronas ou assíncronas, dependendo de você usar o método open() ou openAsync(). Para obter detalhes, consulte “Noções básicas do arquivo AIR” na página 106. Se você definir o parâmetro fileMode como FileMode.READ ou FileMode.UPDATE no método de abertura do objeto FileStream, os dados são lidos no buffer de leitura tão logo você abra o objeto FileStream. Para obter detalhes, consulte “O buffer de leitura e a propriedade bytesAvailable do objeto FileStream” na página 125. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 124 Trabalho com o sistema de arquivos Você pode chamar o método close() do objeto FileStream para fechar o arquivo associado, tornando-o disponível para uso por outros aplicativos. A propriedade position do objeto FileStream A propriedade position do objeto FileStream determina quando os dados são lidos ou gravados no próximo método de leitura ou gravação. Antes de uma operação de leitura ou gravação, defina a propriedade position como qualquer posição válida no arquivo. Por exemplo, o código a seguir grava a seqüência "hello" (na codificação UTF) na posição 8 do arquivo: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.UPDATE); myFileStream.position = 8; myFileStream.writeUTFBytes("hello"); Quando você abre pela primeira vez o objeto FileStream, a propriedade position é definida como 0. Antes de uma operação de leitura, o valor de position deve ser no mínimo 0 e inferior ao número de bytes no arquivo (que são posições existentes no arquivo). O valor da propriedade position é modificado apenas nas seguintes condições: • Quando você define explicitamente a propriedade position. • Quando você chama o método de leitura. • Quando você chama o método de gravação. Quando você chama um método de leitura ou gravação do objeto FileStream, a propriedade position é imediatamente incrementada pelo número de bytes que você lê ou grava. Dependendo do método de leitura usado, a propriedade position também é incrementada pelo número de bytes especificado para leitura ou pelo número de bytes disponível. Quando você chama o método de leitura ou gravação subseqüentemente, ele faz a leitura ou gravação iniciando na nova posição. var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.UPDATE); myFileStream.position = 4000; trace(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); trace(myFileStream.position); // 4200 Há, porém, uma exceção: em um FileStream aberto no modo append, a propriedade position não é alterada após uma chamada de um método de gravação. (No modo append, os dados são sempre gravados no final do arquivo, independentemente do valor da propriedade position.) Em um arquivo aberto para operações assíncronas, a operação de gravação não é concluída antes de a próxima linha de código ser executada. No entanto, você pode chamar vários métodos assíncronos seqüencialmente e o tempo de execução os executa em ordem: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 125 Trabalho com o sistema de arquivos var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.openAsync(myFile, FileMode.WRITE); myFileStream.writeUTFBytes("hello"); myFileStream.writeUTFBytes("world"); myFileStream.addEventListener(Event.CLOSE, closeHandler); myFileStream.close(); trace("started."); closeHandler(event:Event):void { trace("finished."); } A saída trace desse código é a seguinte: started. finished. Você pode especificar o valor position logo após chamar um método de leitura ou gravação (ou a qualquer momento) e a próxima operação de leitura ou gravação ocorrerá no início dessa posição. Por exemplo, observe que o código a seguir define a propriedade position logo após uma chamada para a operação writeBytes() e a position é definida como esse valor (300) mesmo após a operação de gravação ser concluída: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.openAsync(myFile, FileMode.UPDATE); myFileStream.position = 4000; trace(myFileStream.position); // 4000 myFileStream.writeBytes(myByteArray, 0, 200); myFileStream.position = 300; trace(myFileStream.position); // 300 O buffer de leitura e a propriedade bytesAvailable do objeto FileStream Quando o objeto FileStream com recursos de leitura (em que o parâmetro fileMode do método open() ou openAsync() foi definido como READ ou UPDATE) for aberto, o tempo de execução armazena os dados em um buffer interno. O objeto FileStream começa a fazer a leitura de dados no buffer assim que o arquivo for aberto (chamando o método open() ou openAsync() do objeto FileStream). Em um arquivo aberto para operações síncronas (usando o método open()), você sempre poderá definir o ponteiro position em qualquer posição válida (dentro dos limites do arquivo) e iniciar a leitura de qualquer quantidade de dados (dentro dos limites do arquivo), conforme mostra o código a seguir (que supõe que o arquivo contém pelo menos 100 bytes): var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.READ); myFileStream.position = 10; myFileStream.readBytes(myByteArray, 0, 20); myFileStream.position = 89; myFileStream.readBytes(myByteArray, 0, 10); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 126 Trabalho com o sistema de arquivos Quer o arquivo seja aberto para operações síncronas ou assíncronas, os métodos de leitura sempre fazem a leitura dos bytes "disponíveis", representados pela propriedade bytesAvalable. Ao fazer a leitura sincronicamente, todos os bytes do arquivo ficam disponíveis o tempo todo. Ao fazer a leitura assincronicamente, os bytes se tornam disponíveis, iniciando na posição especificada pela propriedade position, em uma série de preenchimentos de buffer assíncronos assinalados por eventos progress. Em arquivos abertos para operações síncronas, a propriedade bytesAvailable é sempre definida para representar o número de bytes da propriedade position no final do arquivo (todos os bytes no arquivo estarão sempre disponíveis para leitura). Em arquivos abertos para operações assíncronas, é necessário assegurar que o buffer de leitura consumiu dados suficientes antes de chamar o método de leitura. Em um arquivo aberto assincronicamente, conforme o andamento da operação de leitura, os dados do arquivo, iniciando na posição especificada quando a operação de leitura iniciou, são adicionados ao buffer, e a propriedade bytesAvailable é incrementada com cada byte lido. A propriedade bytesAvailable indica o número de bytes disponíveis, iniciando com o byte na posição especificada pela propriedade position até o final do buffer. Periodicamente, o objeto FileStream envia um evento progress. Em um arquivo aberto sincronicamente, à medida que os dados se tornam disponíveis no buffer de leitura, o objeto FileStream despacha periodicamente o evento progress. Por exemplo, o código a seguir lê dados em um objeto ByteArray, bytes, conforme é lido no buffer: var bytes:ByteArray = new ByteArray(); var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, FileMode.READ); function progressHandler(event:ProgressEvent):void { myFileStream.readBytes(bytes, myFileStream.position, myFileStream.bytesAvailable); } Em um arquivo aberto assincronicamente, apenas os dados no buffer de leitura podem ser lidos. Além disso, conforme você lê os dados, eles são removidos do buffer de leitura. Em operações de leitura você precisa assegurar que haja dados no buffer de leitura antes de chamar uma operação de leitura. Por exemplo, o código a seguir faz a leitura de 8000 bytes de dados iniciando da posição 4000 no arquivo: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); myFileStream.position = 4000; var str:String = ""; function progressHandler(event:Event):void { if (myFileStream.bytesAvailable > 8000 ) { str += myFileStream.readMultiByte(8000, "iso-8859-1"); } } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 127 Trabalho com o sistema de arquivos Durante a operação de gravação, o objeto FileStream não faz a leitura de dados no buffer de leitura. Quando a operação de gravação estiver concluída (todos os dados no buffer de gravação são gravados no arquivo), o objeto FileStream inicia um novo buffer de leitura (supondo que o objeto FileStream associado foi aberto com recursos de leitura) e inicia a leitura de dados no buffer de leitura, começando da posição especificada pela propriedade position. A propriedade position pode ser a posição do último byte gravado ou pode ser uma posição diferente, se o usuário especificar um valor diferente para o objeto position após a operação de gravação. Programação assíncrona e eventos gerados por um objeto FileStream aberto assincronicamente Quando um arquivo for aberto de modo assíncrono (usando o método openAsync()), os arquivos de leitura e gravação serão executados de modo assíncrono. À medida que os dados são lidos no buffer de leitura e os dados de saída começam a ser gravados, outro código ActionScript pode ser executado. Isso significa que é necessário se registrar para eventos gerados pelo objeto FileStream abertos de modo assíncrono. Registrando-se para o evento progress, você poderá ser notificado quando novos dados se tornarem disponíveis para leitura, como no seguinte código: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(ProgressEvent.PROGRESS, progressHandler); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function progressHandler(event:ProgressEvent):void { str += myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } Você pode fazer a leitura de todos os dados se registrando para o evento complete, como no seguinte código: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function completeHandler(event:Event):void { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } Da mesma maneira que os dados de entrada são colocados em buffer para permitir a leitura assíncrona, os dados que você grava em um fluxo assíncrono são colocados em buffer e gravados no arquivo de forma assíncrona. À medida que os dados são gravados em um arquivo, o objeto FileStream despacha periodicamente o objeto OutputProgressEvent. O objeto OutputProgressEvent inclui a propriedade bytesPending definida pelo número de bytes restantes para gravação. Você pode registrar para que o evento outputProgress seja notificado, já que esse buffer é, na realidade, gravado no arquivo, talvez para exibir uma caixa de diálogo de progresso. No entanto, isso geralmente não é necessário. Especificamente, você pode chamar o método close() sem se importar com os bytes não gravados. O objeto FileStream continuará gravando dados e o evento close será entregue após o byte final ser gravado no arquivo e o arquivo subjacente ser fechado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 128 Trabalho com o sistema de arquivos Formatos de dados e seleção de métodos de leitura e gravação para uso Todo arquivo é um conjunto de bytes em um disco. No ActionScript, os dados de um arquivo sempre podem ser representados como ByteArray. Por exemplo, o código a seguir faz a leitura de dados de um arquivo em um objeto ByteArray chamado bytes: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completeHandler); myFileStream.openAsync(myFile, FileMode.READ); var bytes:ByteArray = new ByteArray(); function completeHandler(event:Event):void { myFileStream.readBytes(bytes, 0, myFileStream.bytesAvailable); } De forma semelhante, o código seguinte grava dados de um ByteArray chamado bytes em um arquivo: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.open(myFile, FileMode.WRITE); myFileStream.writeBytes(bytes, 0, bytes.length); No entanto, normalmente você não quer armazenar dados em um objeto ByteArray do ActionScript. E, geralmente, o arquivo de dados está em um formato de arquivo especificado. Por exemplo, os dados no arquivo podem estar em um formato de arquivo de texto e talvez você deseje representar esses dados em um objeto String. Por esse motivo, a classe FileStream inclui métodos de leitura e gravação para leitura e gravação de dados em outros tipos diferentes dos objetos ByteArray e a partir deles. Por exemplo, o método readMultiByte() permite fazer a leitura de dados de um arquivo e armazená-los em uma seqüência, como no código a seguir: var myFile:File = File.documentsDirectory.resolvePath("AIR Test/test.txt"); var myFileStream:FileStream = new FileStream(); myFileStream.addEventListener(Event.COMPLETE, completed); myFileStream.openAsync(myFile, FileMode.READ); var str:String = ""; function completeHandler(event:Event):void { str = myFileStream.readMultiByte(myFileStream.bytesAvailable, "iso-8859-1"); } O segundo parâmetro do método readMultiByte() especifica o formato de texto que o ActionScript usa para interpretar os dados ("iso-8859-1" no exemplo). O ActionScript oferece suporte às codificações comuns de conjunto de caracteres e elas são listadas na Referência de Linguagem do ActionScript 3.0 (consulte, Conjuntos de caracteres com suporteem http://livedocs.macromedia.com/flex/2/langref/charset-codes.html). A classe FileStream também inclui o método readUTFBytes(), que faz leitura de dados do buffer de leitura em uma seqüência, usando o conjunto de caracteres UTF-8. Como os caracteres no conjunto de caracteres UTF-8 são de tamanho variável, não use readUTFBytes() em um método que responde ao evento progress, já que os dados no final do buffer de leitura podem representar um caractere incompleto. (Isso também é verdadeiro ao usar o método readMultiByte() com uma codificação de caractere de tamanho variável). Por esse motivo, leia o conjunto de dados inteiro quando o objeto FileStream despachar o evento complete. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 129 Trabalho com o sistema de arquivos Também há métodos de gravação semelhantes, writeMultiByte() e writeUTFBytes(), para trabalhar com objetos String e arquivos de texto. Os métodos readUTF() e writeUTF() (não confundir com readUTFBytes() e writeUTFBytes()) também fazem leitura e gravação de dados de texto em um arquivo, mas eles supõem que os dados de texto são precedidos por dados que especificam o tamanho dos dados de texto, o que não é prática comum em arquivos de texto padrão. Alguns arquivos de texto de codificação UTF começam com um caractere "UTF-BOM" (marca de ordem de bytes) que define que a terminação, bem como o formato de codificação (como UTF-16 ou UTF-32). Para obter um exemplo de leitura e gravação de um arquivo de texto, consulte “Exemplo: Leitura de arquivo XML em um objeto XML” na página 130. readObject() e writeObject() são formas convenientes de armazenar e recuperar dados de objetos ActionScript complexos. Os dados são codificados em AMF (ActionScript Message Format). Esse formato é próprio do ActionScript. Outros aplicativos, além de AIR, Flash Player, Flash Media Server e Flex Data Services não têm APIs incorporadas para trabalhar com dados nesse formato. Há mais alguns métodos de leitura e gravação (comoreadDouble() e writeDouble()). No entanto, se você usá-los, certifique-se de que o formato de arquivo corresponde ao formato dos dados definidos por esses métodos. Os formatos de arquivos são normalmente mais complexos do que os formatos de texto simples. Por exemplo, o arquivo MP3 inclui dados compactados que só podem ser interpretados com a descompactação e os algoritmos de decodificação específicos para arquivos MP3. Arquivos MP3 também podem incluir marcas ID3 que contêm informações de metatag sobre o arquivo (como o título e o artista de uma canção). Há várias versões do formato ID3, mas a mais simples (versão ID3 1) é discutida na seção “Exemplo: Leitura e gravação de dados com acesso aleatório” na página 131. Outros formatos de arquivo (de imagens, bancos de dados, documentos de aplicativos etc.) têm estruturas diferentes e, para trabalhar com os respectivos dados no ActionScript, você deve saber como os dados são estruturados. Uso dos métodos load() e save() O Flash Player 10 adicionou os métodos load() e save() à classe FileReference. Esses métodos também estão no AIR 1.5 e a classe File herda os métodos da classe FileReference. Esses métodos foram projetados para fornecer um meio seguro para usuários carregarem e salvarem dados de arquivo em Flash Player. No entanto, os aplicativos AIR também podem usar esses métodos como uma maneira fácil de carregar e salvar arquivos de forma assíncrona. Por exemplo, o código a seguir salva uma seqüência de caracteres em um arquivo de texto: var file:File = File.applicationStorageDirectory.resolvePath("test.txt"); var str:String = "Hello."; file.addEventListener(Event.COMPLETE, fileSaved); file.save(str); function fileSaved(event:Event):void { trace("Done."); } O parâmetro data do método save() pode usar um valor String, XML ou ByteArray. Quando o argumento é um valor String ou XML, o método salva o arquivo como arquivo de texto criptografado UTF-8. Quando esse exemplo de código é executado, o aplicativo exibe uma caixa de diálogo em que o usuário seleciona o destino do arquivo salvo. O código a seguir carrega uma seqüência de caracteres de um arquivo de texto codificado em UTF-8. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 130 Trabalho com o sistema de arquivos var file:File = File.applicationStorageDirectory.resolvePath("test.txt"); file.addEventListener(Event.COMPLETE, loaded); file.load(); var str:String; function loaded(event:Event):void { var bytes:ByteArray = file.data; str = bytes.readUTFBytes(bytes.length); trace(str); } A classe FileStream fornece mais funcionalidade do que os métodos load() e save(). • Usando a classe FileStream, você pode ler e gravar dados de forma síncrona e assíncrona. • O uso da classe FileStream permite gravar em um arquivo de forma incremental. • O uso da classe FileStream permite abrir um arquivo para acesso aleatório (para leitura e gravação em qualquer seção do arquivo). • A classe FileStream permite especificar o tipo de acesso que você tem ao arquivo, definindo o parâmetro fileMode do método open() ou openAsync(). • A classe FileStream permite salvar dados em arquivos sem apresentar ao usuário uma caixa de diálogo Abrir ou Salvar. • Você pode usar diretamente tipos diferentes de matrizes de bytes ao ler dados com a classe FileStream. Exemplo: Leitura de arquivo XML em um objeto XML O exemplo a seguir demonstra como fazer a leitura e a gravação de um arquivo de texto contendo dados XML. Para ler o arquivo, inicialize os objetos File e FileStream, chame o método readUTFBytes() do FileStream e converta a seqüência em um objeto XML: var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream:FileStream = new FileStream(); fileStream.open(file, FileMode.READ); var prefsXML:XML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable)); fileStream.close(); De modo semelhante, gravar dados no arquivo é tão fácil quanto configurar os objetos File e FileStream apropriados e, em seguida, chamar um método de gravação do objeto FileStream. Passe a versão de seqüência dos dados XML para o método de gravação, como no código seguinte: var prefsXML:XML = <prefs><autoSave>true</autoSave></prefs>; var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); fileStream = new FileStream(); fileStream.open(file, FileMode.WRITE); var outputString:String = '<?xml version="1.0" encoding="utf-8"?>\n'; outputString += prefsXML.toXMLString(); fileStream.writeUTFBytes(outputString); fileStream.close(); Esses exemplos usam os métodos readUTFBytes() e writeUTFBytes(), porque consideram que os arquivos estejam no formato UTF-8. Caso contrário, você pode precisar usar um método diferente (consulte “Formatos de dados e seleção de métodos de leitura e gravação para uso” na página 128). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 131 Trabalho com o sistema de arquivos Os exemplos anteriores usam objetos FileStream abertos para operação síncrona. Você também pode abrir arquivos para operações assíncronas (que dependem das funções de ouvinte de evento para responder aos eventos). Por exemplo, o código a seguir mostra como fazer a leitura de um arquivo XML de modo assíncrono: var file:File = File.documentsDirectory.resolvePath("AIR Test/preferences.xml"); var fileStream:FileStream = new FileStream(); fileStream.addEventListener(Event.COMPLETE, processXMLData); fileStream.openAsync(file, FileMode.READ); var prefsXML:XML; function processXMLData(event:Event):void { prefsXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable)); fileStream.close(); } O método processXMLData() é chamado quando o arquivo inteiro é lido no buffer de leitura (quando o objeto FileStream despacha o evento complete). Ele chama o método readUTFBytes() para obter uma versão de seqüência dos dados lidos e cria um objeto XML, prefsXML, com base nessa seqüência. Exemplo: Leitura e gravação de dados com acesso aleatório Arquivos MP3 podem incluir marcas ID3, que são seções no início ou no final do arquivo, contendo metadados que identificam a gravação. O próprio formato de marca ID3 tem revisões diferentes. Este exemplo descreve como fazer a leitura e a gravação de um arquivo MP3 que contém o formato ID3 mais simples (ID3 versão 1.0) usando o "acesso aleatório a dados do arquivo", o que significa que ele lê a partir de e grava em locais arbitrários no arquivo. O arquivo MP3 que contém uma marca ID3 versão 1 inclui dados ID3 no final do arquivo, nos últimos 128 bytes. Ao acessar um arquivo para acesso de leitura e gravação aleatório, é importante especificar FileMode.UPDATE como o parâmetro fileMode do método open() ou openAsync(): var file:File = File.documentsDirectory.resolvePath("My Music/Sample ID3 v1.mp3"); var fileStr:FileStream = new FileStream(); fileStr.open(file, FileMode.UPDATE); Isso permite ler e gravar no arquivo. Ao abrir o arquivo, você pode definir o ponteiro position para a posição de 128 bytes antes do final do arquivo: fileStr.position = file.size - 128; Esse código define a propriedade position para esse local no arquivo, porque o formato ID3 v1.0 especifica que os dados da marca ID3 são armazenados nos últimos 128 bytes do arquivo. A especificação também diz o seguinte: • Os primeiros 3 bytes da marca contêm a seqüência "TAG". • Os 30 caracteres seguintes contêm o título da trilha MP3, como uma seqüência. • Os 30 caracteres seguintes contêm o nome do artista, como uma seqüência. • Os 30 caracteres seguintes contêm o nome do álbum, como uma seqüência. • Os 4 caracteres seguintes contêm o ano, como uma seqüência. • Os 30 caracteres seguintes contêm o comentário, como uma seqüência. • O byte seguinte contém um código indicando o gênero da trilha. • Todos os dados de texto estão no formato ISO 8859-1. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 132 Trabalho com o sistema de arquivos O método id3TagRead() verifica os dados após serem lidos (no evento complete): function id3TagRead():void { if (fileStr.readMultiByte(3, "iso-8859-1").match(/tag/i)) { var id3Title:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Artist:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Album:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3Year:String = fileStr.readMultiByte(4, "iso-8859-1"); var id3Comment:String = fileStr.readMultiByte(30, "iso-8859-1"); var id3GenreCode:String = fileStr.readByte().toString(10); } } Você também pode realizar uma gravação com acesso aleatório no arquivo. Por exemplo, você pode analisar a variável id3Title para assegurar que ela esteja com as maiúsculas e minúsculas corretas (usando métodos da classe String) e, em seguida, fazer a gravação de uma seqüência modificada, chamada newTitle, no arquivo, como no seguinte: fileStr.position = file.length - 125; // 128 - 3 fileStr.writeMultiByte(newTitle, "iso-8859-1"); Para corresponder à versão 1 padrão do ID3, o tamanho da seqüência newTitle deve ter 30 caracteres, preenchidos no final com o caractere de código 0 (String.fromCharCode(0)). 133 Capítulo 15: Arrastar e soltar Use as classes na API de arrastar e soltar para suportar gestos de arrastar e soltar de interface do usuário. Um gesto neste sentido é uma ação do usuário, mediada pelo sistema operacional e seu aplicativo, expressando uma intenção de copiar, mover ou vincular informações. Um gesto de arrastar para fora ocorre quando o usuário arrasta um objeto para fora de um componente ou aplicativo. Um gesto de arrastar para dentro ocorre quando o usuário arrasta para dentro um objeto de fora um componente ou aplicativo. Com a API de arrastar e soltar, você pode permitir que um usuário arraste dados entre aplicativos e entre componentes dentro de um aplicativo. Os formatos de transferência suportados incluem: • Bitmaps • Arquivos • Texto formatado em HTML • Texto • Dados em RTF • URLs • Objetos serializados • Referências a objetos (válido somente dentro do aplicativo originador) Informações online adicionais sobre arrastar e soltar Você pode encontrar mais informações sobre como trabalhar com a API de arrastar e soltar nessas fontes: Início rápido (Adobe AIR Developer Connection) • Suporte a arrastar e soltar e copiar e colar Referência de Linguagem • NativeDragManager • NativeDragOptions • Clipboard • NativeDragEvent Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (procurar 'AIR arrastar e soltar') Conceitos básicos de arrastar e soltar A API de arrastar e soltar contém as seguintes classes: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 134 Arrastar e soltar Pacote Classes flash.desktop • NativeDragManager • NativeDragOptions • Clipboard • NativeDragActions • ClipboardFormat • ClipboardTransferModes Constantes usadas com a API de arrastar e soltar são definidas nas seguintes classes: flash.events • NativeDragActions • ClipboardFormat • ClipboardTransferModes NativeDragEvent Estágios do gesto de arrastar e soltar O gesto de arrastar e soltar possui três estágios: Iniciação Um usuário inicia uma operação de arrastar e soltar arrastando de um componente, ou um item em um componente, enquanto mantém pressionado o botão do mouse. O componente que é a origem do item arrastado é normalmente designado como o iniciador do ação de arrastar e despacha eventos nativeDragStart e nativeDragComplete. Um aplicativo do Adobe® AIR™ inicia uma operação de arrastar chamando o método NativeDragManager.doDrag() em resposta a um evento mouseDown ou mouseMove. Se a operação de arrastar for iniciada de fora do aplicativo do AIR, não haverá nenhum objeto iniciador para despachar os eventos nativeDragStart ou nativeDragComplete. Arrastar Ao segurar o botão do mouse, o usuário move o cursor do mouse para outro componente, aplicativo ou a área de trabalho. Uma vez que a ação de arrastar esteja em andamento, o objeto iniciador despacha eventos nativeDragUpdate. Quando o usuário move o mouse sobre um possível destino no qual soltar em um aplicativo do AIR, o destino despacha um evento nativeDragEnter. O manipulador de eventos pode inspecionar o objeto de evento para determinar se os dados arrastados estão disponíveis em um formato que o destino aceite e, se sim, permitir ao usuário soltar os dados nele chamando o método NativeDragManager.acceptDragDrop(). Enquanto o gesto de arrastar permanece sobre um objeto interativo, esse objeto despacha eventos nativeDragOver. Quando o gesto de arrastar deixa o objeto interativo, ele despacha um evento nativeDragExit. Soltar O usuário libera o mouse sobre um destino de soltar aceitável. Se o destino for um componente ou aplicativo do AIR, o objeto de destino despacha um evento nativeDragDrop. O manipulador de eventos pode acessar os dados transferidos do objeto de evento. Se o destino estiver fora do AIR, o sistema operacional ou outro aplicativo manipulará a ação de soltar. Nos dois casos, o objeto iniciador despacha um evento nativeDragComplete (se a ação de arrastar tiver iniciado de dentro do AIR). A classe NativeDragManager controla os gestos de arrastar para dentro e para fora. Todos os membros da classe NativeDragManager são estáticos, não crie uma instância dessa classe. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 135 Arrastar e soltar O objeto Clipboard Os dados arrastados para dentro ou para fora de um aplicativo ou componente são contidos em um objeto Clipboard. Um único objeto Clipboard pode disponibilizar representações diferentes das mesmas informações para aumentar a probabilidade de que outro aplicativo possa entender e usar os dados. Por exemplo, uma imagem poderia ser incluída como dados de imagem, como um objeto Bitmap serializado e como um arquivo. O processamento dos dados em um formato pode ser adiado para uma função de processamento não chamada até que os dados sejam lidos. Após um gesto de arrastar ter sido iniciado, o objeto Clipboard pode apenas ser acessado de dentro de um manipulador de eventos para os eventos nativeDragEnter, nativeDragOver e nativeDragDrop. Após o gesto de arrastar ter sido finalizado, o objeto Clipboard não poderá ser lido ou reutilizado. Um objeto de aplicativo pode ser transferido como uma referência e um objeto serializado. As referências são válidas apenas dentro do aplicativo originador. Transferências de objetos serializados são válidas entre aplicativos do AIR, mas podem apenas ser usadas com objetos que permanecem válidos quando serializados e desserializados. Objetos serializados são convertidos no Action Message Format para ActionScript 3 (AMF3), um formato de transferência de dados baseado em seqüência de caracteres. Trabalho com a estrutura do Flex Na maioria dos casos, é melhor usar a API de arrastar e soltar do Adobe® Flex™ ao criar aplicativos do Flex. A estrutura do Flex fornece um conjunto de recursos equivalente quando um aplicativo do Flex é executado no AIR (ela usa o NativeDragManager do AIR internamente). O Flex também mantém um conjunto de recursos mais limitado quando um aplicativo ou componente está em execução dentro do ambiente do navegador mais restritivo. As classes do AIR não podem ser usadas em componentes ou aplicativos executados fora do ambiente de tempo de execução do AIR. Suporte ao gesto de arrastar para fora Para suportar o gesto de arrastar para fora, você deve criar um objeto Clipboard em resposta a um evento mouseDown e enviá-lo ao método NativeDragManager.doDrag(). Seu aplicativo pode então ouvir o evento nativeDragComplete sobre o objeto iniciador para determinar que ação tomar quando o usuário conclui ou abandona o gesto. Preparação de dados para transferência Para preparar dados ou um objeto para arrastar, crie um objeto Clipboard e adicione as informações a serem transferidas em um ou mais formatos. Você pode usar os formatos de dados padrão para transmitir dados, que podem ser traduzidos automaticamente para formatos nativos da área de transferência, e formatos definidos por aplicativo para transmitir objetos. Se, do ponto de vista computacional, for caro converter as informações a serem transferidas para um formato particular, você pode fornecer o nome de uma função de manipulador para realizar a conversão. A função é chamada se, e apenas se, o componente ou aplicativo receptor ler o formato associado. Para obter mais informações sobre os formatos da área de transferência, consulte o capítulo Copiar e colar de Programação do ActionScript 3.0 (http://www.adobe.com/go/learn_fl_cs4_programmingAS3_en). O exemplo a seguir ilustra como criar um objeto Clipboard contendo um bitmap em vários formatos: um objeto Bitmap, um formato de bitmap nativo e um formato da lista de arquivo contendo o arquivo do qual o bitmap foi originalmente carregado: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 136 Arrastar e soltar import flash.desktop.Clipboard; import flash.display.Bitmap; import flash.filesystem.File; public function createClipboard(image:Bitmap, sourceFile:File):Clipboard{ var transfer:Clipboard = new Clipboard(); transfer.setData("CUSTOM_BITMAP", image, true); //Flash object by value and by reference transfer.setData(ClipboardFormats.BITMAP_FORMAT, image.bitmapData, false); transfer.setData(ClipboardFormats.FILE_LIST_FORMAT, new Array(sourceFile), false); return transfer; } Início de uma operação de arrastar e soltar Para iniciar uma operação de arrastar, chame o método NativeDragManager.doDrag() em resposta a um evento de mouse para baixo. O método doDrag() é um método estático que adota os seguintes parâmetros: Parâmetro Descrição iniciador O objeto do qual a ação de arrastar se origina e que despacha os eventos dragStart e dragComplete. O iniciador deve ser um objeto interativo. área de transferência O objeto Clipboard contendo os dados a serem transferidos. O objeto Clipboard é referenciado nos objetos NativeDragEvent despachados durante a seqüência de arrastar e soltar. dragImage (Opcional) Um objeto BitmapData a ser exibido durante a ação de arrastar. A imagem pode especificar um valor alpha. (Observação: o Microsoft Windows sempre aplica uma atenuação alfa fixa a imagens de arrastar). deslocamento (Opcional) Um objeto Point especificando o deslocamento da imagem de arrastar do ponto ativo do mouse. Use coordenadas negativas para mover a imagem de arrastar para cima e à esquerda com relação ao cursor do mouse. Se nenhum deslocamento for fornecido, o canto superior esquerdo da imagem de arrastar será posicionado no ponto ativo do mouse. actionsAllowed (Opcional) Um objeto NativeDragOptions especificando que ações (copiar, mover ou vincular) são válidas para a operação de arrastar. Se nenhum argumento for fornecido, todas as ações serão permitidas. O objeto DragOptions é referenciado em objetos NativeDragEvent para permitir que um possível destino da ação de arrastar verifique se as ações permitidas são compatíveis com o objetivo do componente de destino. Por exemplo, um componente “trash” pode aceitar apenas gestos de arrastar que permitem a ação de mover. O exemplo a seguir ilustra como iniciar uma operação de arrastar para um objeto de bitmap carregado de um arquivo. O exemplo carrega uma imagem e, em um evento mouseDown, inicia a operação de arrastar. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 137 Arrastar e soltar package { import flash.desktop.NativeDragManager; import mx.core.UIComponent; import flash.display.Sprite; import flash.display.Loader; import flash.system.LoaderContext; import flash.net.URLRequest; import flash.geom.Point; import flash.desktop.Clipboard; import flash.display.Bitmap; import flash.filesystem.File; import flash.events.Event; import flash.events.MouseEvent; public class DragOutExample extends UIComponent Sprite { protected var fileURL:String = "app:/image.jpg"; protected var display:Bitmap; private function init():void { loadImage(); } private function onMouseDown(event:MouseEvent):void { var bitmapFile:File = new File(fileURL); var transferObject:Clipboard = createClipboard(display, bitmapFile); NativeDragManager.doDrag(this, transferObject, display.bitmapData, new Point(-mouseX,-mouseY)); } public function createClipboard(image:Bitmap, sourceFile:File):Clipboard { var transfer:Clipboard = new Clipboard(); transfer.setData("bitmap", image, true); // ActionScript 3 Bitmap object by value and by reference transfer.setData(ClipboardFormats.BITMAP_FORMAT, image.bitmapData, false); // Standard BitmapData format transfer.setData(ClipboardFormats.FILE_LIST_FORMAT, DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 138 Arrastar e soltar new Array(sourceFile), false); // Standard file list format return transfer; } private function loadImage():void { var url:URLRequest = new URLRequest(fileURL); var loader:Loader = new Loader(); loader.load(url,new LoaderContext()); loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); } private function onLoadComplete(event:Event):void { display = event.target.loader.content; var flexWrapper:UIComponent = new UIComponent(); flexWrapper.addChild(event.target.loader.content); addChild(flexWrapper); flexWrapper.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); } } } Conclusão de uma transferência de arrastar para fora Quando um usuário solta o item arrastado liberando o mouse, o objeto iniciador despacha um evento nativeDragComplete. Você pode verificar a propriedade dropAction do objeto de evento e executar a ação apropriada. Por exemplo, se a ação for NativeDragAction.MOVE, você poderia remover o item de origem de seu local original. O usuário pode abandonar um gesto de arrastar liberando o botão do mouse enquanto o cursor está fora de um destino de arrastar aceitável. O gerente de arrastar define a propriedade dropAction para um gesto abandonado a NativeDragAction.NONE. Suporte ao gesto de arrastar para dentro Para suportar o gesto de arrastar para dentro, seu aplicativo (ou, mais tipicamente, um componente visual do seu aplicativo) deve responder aos eventos nativeDragEnter ou nativeDragOver. Etapas em uma operação típica de arrastar A seguinte seqüência de eventos é típica para uma operação de arrastar: 1 O usuário arrasta um objeto da área de transferência sobre um componente. 2 O componente despacha um evento nativeDragEnter. 3 O manipulador de eventos nativeDragEnter examina o objeto de evento para verificar os formatos de dados disponíveis e as ações permitidas. Se o componente pode manipular a ação de soltar, ele chama NativeDragManager.acceptDragDrop(). 4 O NativeDragManager altera o cursor do mouse para indicar que o objeto pode ser solto. 5 O usuário solta o objeto sobre o componente. 6 O componente receptor despacha um evento nativeDragDrop. 7 O componente receptor lê os dados no formato desejado do objeto Clipboard dentro do objeto de evento. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 139 Arrastar e soltar 8 Se o gesto de arrastar foi originado no aplicativo do AIR, o objeto interativo iniciador despacha um evento nativeDragComplete. Se o gesto foi originado fora do AIR, nenhum comentário é enviado. Reconhecimento de um gesto de arrastar para dentro Quando um usuário arrasta um item da área de transferência para dentro dos limites de um componente visual, o componente despacha eventos nativeDragEnter e nativeDragOver. Para determinar se o componente pode aceitar o item da área de transferência, os manipuladores para esses eventos pode verificar as propriedades clipboard e allowedActions do objeto de evento. Para sinalizar que o componente pode aceitar a ação de soltar, o manipulador de eventos deve chamar o método NativeDragManager.acceptDragDrop(), transmitindo uma referência ao componente receptor. Se mais de um ouvinte de evento registrado chamar o método acceptDragDrop(), o último manipulador da lista tem precedência. A chamada acceptDragDrop() permanece válida até que o mouse deixe os limites do objeto recebedor, disparando o evento nativeDragExit. Se mais de uma ação for permitida no parâmetro allowedActions transmitido a doDrag(), o usuário pode indicar qual das ações permitidas pretende mantendo pressionada uma tecla de modificador. O gerente de arrastar altera a imagem do cursor para dizer ao usuário que ação ocorreria se ele concluísse a ação de soltar. A ação pretendida é reportado pela propriedade dropAction do evento NativeDragEvent. O conjunto de ação para um gesto de arrastar é apenas consultivo. Os componentes envolvidos na transferência devem implementar o comportamento apropriado. Para completar uma ação de mover, por exemplo, o iniciador de arrastar poderia remover o item arrastado e o destino de soltar poderia adicioná-lo. Seu destino de arrastar pode limitar a ação de soltar para uma das três ações possíveis definindo a propriedade dropAction da classe NativeDragManager. Se um usuário tenta escolher uma ação diferente usando o teclado, NativeDragManager exibe o cursor unavailable. Define a propriedade dropAction nos manipuladores para os eventos nativeDragEnter e nativeDragOver. O exemplo a seguir ilustra um manipulador de eventos para um evento nativeDragEnter ou nativeDragOver. Esse manipulador aceita apenas um gesto de arrastar para dentro se a área de transferência sendo arrastada contiver dados em formato de texto. import flash.desktop.NativeDragManager; import flash.events.NativeDragEvent; public function onDragIn(event:NativeDragEvent):void{ NativeDragManager.dropAction = NativeDragActions.MOVE; if(event.clipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)){ NativeDragManager.acceptDragDrop(this); //'this' is the receiving component } } Conclusão da ação de soltar Quando o usuário solta um item arrastado em um objeto interativo que aceitou o gesto, o objeto interativo despacha um evento nativeDragDrop. O manipulador desse evento pode extrair os dados a propriedade clipboard do objeto de evento. Quando a área de transferência contém um formato definido por aplicativo, o parâmetro transferMode transmitido ao método getData() do objeto Clipboard determina se o gerenciador de arrastar retorna uma referência ou uma versão serializada do objeto. O exemplo a seguir ilustra um manipulador de eventos para o evento nativeDragDrop: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 140 Arrastar e soltar import flash.desktop.Clipboard; import flash.events.NativeDragEvent; public function onDrop(event:NativeDragEvent):void { if (event.clipboard.hasFormat(ClipboardFormats.TEXT_FORMAT)) { var text:String = String(event.clipboard.getData(ClipboardFormats.TEXT_FORMAT, ClipboardTransferMode.ORIGINAL_PREFERRED)); } Depois que o manipulador de eventos for encerrado, o objeto Clipboard não será mais válido. Qualquer tentativa de acessar o objeto ou seus dados gera um erro. Atualização da aparência visual de um componente Um componente pode atualizar sua aparência visual com base nos eventos NativeDragEvent. A tabela a seguir descreve os tipos de alterações que um componente típico faria em resposta aos diferentes eventos: Evento Descrição nativeDragStart O objeto interativo iniciante pode usar o evento nativeDragStart para fornecer comentários visuais que o gesto de arrastar originou desse objeto interativo. nativeDragUpdate O objeto interativo iniciante pode usar o evento nativeDragUpdate para atualizar seu estado durante o gesto. nativeDragEnter Um possível objeto interativo receptor pode usar esse evento para assumir o foco ou indicar visualmente que ele pode ou não aceitar a ação de soltar. nativeDragOver Um possível objeto interativo receptor pode usar esse evento para responder ao movimento do mouse dentro do objeto interativo, como quando o mouse insere uma região “ativa” de um componente complexo, como uma exibição de mapa de rua. nativeDragExit Um possível objeto interativo receptor pode usar esse evento para restaurar seu estado quando um gesto de arrastar se move para fora de seus limites. nativeDragComplete O objeto interativo iniciante pode usar esse evento para atualizar seu modelo de dados associado, como removendo um item de uma lista e para restaurar seu estado visual. Rastreamento da posição do mouse durante um gesto de arrastar para dentro Enquanto um gesto de arrastar permanece sobre um componente, esse componente despacha eventos nativeDragOver. Esses eventos são despachados a cada poucos milissegundos e também sempre que o mouse se move. O objeto de evento nativeDragOver pode ser usado para determinar a posição do mouse sobre o componente. Ter acesso à posição do mouse pode ser útil em situações onde o componente receptor é complexo, mas não é formado de subcomponentes. Por exemplo, se seu aplicativo exibiu um bitmap contendo um mapa de rua e você desejava realçar zonas no mapa quando o usuário arrastasse informações a eles, você poderia usar as coordenadas do mouse reportadas no evento nativeDragOver para rastrear a posição do mouse no mapa. HTML arrastar e soltar Para arrastar dados para dentro e fora de um aplicativo baseado em HTML (ou para dentro e fora do HTML exibido em um HTMLLoader), você pode usar eventos de arrastar e soltar HTML. A API de arrastar e soltar HTML permite que você arraste para e de elementos DOM no conteúdo HTML. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 141 Arrastar e soltar Nota: Você também pode usar as APIs NativeDragEvent e NativeDragManager do AIR ouvindo eventos no objeto HTMLLoader contendo o conteúdo HTML. No entanto, a API HTML é melhor integrada com o DOM HTML e oferece a você controle do comportamento padrão. Comportamento padrão de arrastar e soltar O ambiente HTML fornece o comportamento padrão para gestos de arrastar e soltar envolvendo texto, imagens e URLs. Usando o comportamento padrão, você sempre pode arrastar esses tipos de dados para fora de um elemento. No entanto, você pode apenas arrastar texto em um elemento e apenas a elementos em uma região editável de uma página. Quando você arrasta texto entre ou dentro de regiões editáveis de uma página, o comportamento padrão executa uma ação de mover. Quando você arrasta texto para uma região editável de uma região não-editável ou de fora do aplicativo, o comportamento padrão executa uma ação de copiar. Você pode substituir o comportamento padrão manipulando os eventos de arrastar e soltar sozinho. Para cancelar o comportamento padrão, você deve chamar os métodos preventDefault() dos objetos despachados para os eventos de arrastar e soltar. Você pode então inserir dados no destino de soltar e remover dados da origem de arrastar conforme necessário para executar a ação escolhida. Por padrão, o usuário pode selecionar e arrastar qualquer texto e arrastar imagens e links. Você pode usar a propriedade WebKit CSS, -webkit-user-select, para controlar como qualquer elemento HTML pode ser selecionado. Por exemplo, se você definir -webkit-user-select como none, o conteúdo do elemento não podem ser selecionados e, portanto, não podem ser arrastados. Você também pode usar a propriedade CSS -webkit-user-drag para controlar se um elemento como um todo pode ser arrastado. No entanto, o conteúdo do elemento é tratado separadamente. O usuário poderia ainda arrastar uma parte selecionada do texto. Para obter mais informações, consulte “Extensões para o CSS” na página 231. Eventos de arrastar e soltar em HTML Os eventos despachados pelo elemento iniciador do qual uma ação de arrastar se origina são: Evento Descrição dragstart Despachado quando o usuário inicia o gesto de arrastar. O manipulador desse evento pode impedir a ação de arrastar, se necessário, chamando o método preventDefault() do objeto de evento. Para controlar se os dados arrastados podem ser copiados, vinculados ou movidos, defina a propriedade effectAllowed. Texto, imagens e links selecionados são colocados na área de transferência pelo comportamento padrão, mas você pode definir dados diferentes para o gesto de arrastar usando a propriedade dataTransfer do objeto de evento. arrastar Despachado continuamente durante o gesto de arrastar. dragend Despachado quando o usuário libera o botão do mouse para encerrar o gesto de arrastar. Os eventos despachados por um destino de arrastar são: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 142 Arrastar e soltar Evento Descrição dragover Despachado continuamente enquanto o gesto de arrastar permanece dentro dos limites do elemento. O manipulador para esse evento deve definir a propriedade dataTransfer.dropEffect para indicar se a ação de soltar resultará em uma ação de copiar, mover ou vincular se o usuário liberar o mouse. dragenter Despachado quando o gesto de soltar entrar nos limites de um elemento. Se você alterar alguma propriedade de um objeto dataTransfer em um manipulador de eventos dragenter, essas alterações serão rapidamente substituídas pelo próximo evento dragover. Por outro lado, existe um pequeno atraso entre um evento dragenter e o primeiro dragover que pode fazer com que o cursor pisque se diferentes propriedades forem definidas. Em vários casos, você pode usar o mesmo manipulador de eventos para ambos os eventos. dragleave Despachado quando o gesto de arrastar deixa os limites do elemento. drop Despachado quando o usuário solta os dados no elemento. Os dados sendo arrastados podem apenas ser acessados dentro do manipulador desse evento. O objeto de evento despachado em resposta a esses eventos é similar a um evento do mouse. Você pode usar propriedades de evento de mouse como (clientX, clientY) e (screenX, screenY), para determinar a posição do mouse. A propriedade mais importante de um objeto de evento arrastar é dataTransfer, que contém os dados que estão sendo arrastados. O objeto dataTransfer em si possui as seguintes propriedades e métodos: Propriedade ou método Descrição effectAllowed O efeito permitido pela origem da ação de arrastar. Normalmente, o manipulador do evento dragstart define esse valor. Consulte “Efeitos de arrastar em HTML” na página 143. dropEffect O efeito escolhido pelo destino ou usuário. Se você define dropEffect em um manipulador de eventos dragover ou dragenter, o AIR atualiza o cursor do mouse para indicar o efeito que ocorre se o usuário libera o mouse. Se a definição de dropEffect não corresponder a um dos efeitos permitidos, nenhuma ação de soltar será permitida e o cursor unavailable será exibido. Se não tiver definido dropEffect em resposta a um evento dragover ou dragenter mais recente, o usuário poderá escolher dentre os efeitos permitidos com as teclas do modificador do sistema operacional padrão. O efeito final é relatado pela propriedade dropEffect do objeto despachado para dragend. Se o usuário abandonar a ação de soltar liberando o mouse fora de um destino aceitável, dropEffect será definido como none. tipos Uma matriz contendo as seqüências de caracteres de tipo MIME para cada formato de dados é apresentada no objeto dataTransfer. getData(mimeType) Obtém os dados no formato especificado pelo parâmetro mimeType. O método getData() pode apenas ser chamado em resposta ao evento drop. setData(mimeType) Adiciona dados a dataTransfer no formato especificado pelo parâmetro mimeType. Você pode adicionar dados em vários formatos chamando setData() para cada tipo MIME. Qualquer dado colocado no objeto dataTransfer pelo comportamento de arrastar padrão é limpo. O método setData() pode apenas ser chamado em resposta ao evento dragstart. clearData(mimeType) Limpa qualquer dado no formato especificado pelo parâmetro mimeType. setDragImage(image, offsetX, offsetY) Define uma imagem de arrastar personalizada. O método setDragImage() pode apenas ser chamado em resposta ao evento dragstart. Tipos MIME para arrastar e soltar HTML Os tipos MIME a usar com o objeto dataTransfer de um evento arrastar e soltar HTML incluem: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 143 Arrastar e soltar Formato de dados Tipo MIME Texto "text/plain" HTML "text/html" URL "text/uri-list" Bitmap "image/x-vnd.adobe.air.bitmap" Lista de arquivos "application/x-vnd.adobe.air.file-list" Você também pode usar outras seqüências de caracteres MIME, incluindo as definidas por aplicativo. No entanto, outros aplicativos não podem reconhecer ou usar os dados transferidos. É sua responsabilidade adicionar dados ao objeto dataTransfer no formato esperado. Importante: Apenas código em execução na caixa de proteção do aplicativo pode acessar arquivos soltos. Tentar ler ou definir qualquer propriedade de um objeto File em uma caixa de proteção de não-aplicativo gera um erro de segurança. Consulte “Tratamento de arquivos soltos em caixas de proteção HTML de não-aplicativo” na página 147 para obter mais informações. Efeitos de arrastar em HTML O iniciador do gesto de arrastar pode limitar os efeitos de arrastar permitido definindo a propriedade dataTransfer.effectAllowed no manipulador para o evento dragstart. Os seguintes valores de seqüências de caracteres podem ser usados: Valor de string Descrição "none" Nenhuma operação de arrastar é permitida. "copy" Os dados serão copiados ao destino, deixando o original no lugar. "link" Os dados serão compartilhados com o destino de soltar usando um link de volta ao original. "mover” Os dados serão copiados para o destino e removidos do local original. "copyLink" Os dados podem ser copiados ou vinculados. "copyMove" Os dados podem ser copiados ou movidos. "linkMove" Os dados podem ser vinculados ou movidos. "all" Os dados podem ser copiados, movidos ou vinculados. All é o efeito padrão quando você impede o comportamento padrão. O destino do gesto de arrastar pode definir a propriedade dataTransfer.dropEffect para indicar a ação tomada se o usuário concluir a ação de soltar. Se o efeito de soltar for uma das ações permitidas, o sistema exibe o cursor apropriado de copiar, mover ou vincular. Caso contrário, o sistema exibe o cursor unavailable. Se nenhum efeito de soltar for definido pelo destino, o usuário poderá escolher dentre as ações permitidas com as teclas do modificador. Defina o valor dropEffect nos manipuladores para os eventos dragover e dragenter: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 144 Arrastar e soltar function doDragStart(event) { event.dataTransfer.setData("text/plain","Text to drag"); event.dataTransfer.effectAllowed = "copyMove"; } function doDragOver(event) { event.dataTransfer.dropEffect = "copy"; } function doDragEnter(event) { event.dataTransfer.dropEffect = "copy"; } Nota: Embora você deva sempre definir a propriedade dropEffect no manipulador para dragenter, esteja ciente que o próximo evento dragover redefine a propriedade para seu valor padrão. Defina dropEffect em resposta aos dois eventos. Arrastar dados para fora de um elemento HTML O comportamento padrão permite que a maior parte do conteúdo em uma página HTML seja copiada pela ação de arrastar. Você pode controlar o conteúdo permitido a ser arrastado usando as propriedades CSS -webkit-userselect e -webkit-user-drag. Substitua o comportamento padrão de arrastar para fora no manipulador para o evento dragstart. Chame o método setData() da propriedade dataTransfer do objeto de evento para colocar seus próprios dados no gesto de arrastar. Para indicar que efeitos de arrastar um objeto de origem suporta quando você não está contando com o comportamento padrão, define a propriedade dataTransfer.effectAllowed do objeto de evento despachado para o evento dragstart. Você pode escolher qualquer combinação de efeitos. Por exemplo, se um elemento de origem suportar os efeitos copy e link, defina a propriedade como "copyLink". Definição dos dados arrastados Adicione os dados para o gesto de arrastar no manipulador para o evento dragstart com a propriedade dataTransfer. Use o método dataTransfer.setData() para colocar dados na área de transferência, transmitindo o tipo MIME e os dados a transferir. Por exemplo, se você tinha um elemento de imagem no seu aplicativo, com a id imageOfGeorge, você poderia usar o seguinte manipulador de eventos dragstart. Esse exemplo adiciona representações de uma imagem de George em vários formatos de dados, que aumenta a probabilidade de que outros aplicativos possam usar os dados arrastados. function dragStartHandler(event){ event.dataTransfer.effectAllowed = "copy"; var dragImage = document.getElementById("imageOfGeorge"); var dragFile = new air.File(dragImage.src); event.dataTransfer.setData("text/plain","A picture of George"); event.dataTransfer.setData("image/x-vnd.adobe.air.bitmap", dragImage); event.dataTransfer.setData("application/x-vnd.adobe.air.file-list", new Array(dragFile)); } Nota: Quando você chama o método setData() de objeto dataTransfer, nenhum dado é adicionado pelo comportamento padrão de arrastar e soltar. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 145 Arrastar e soltar Arrastar dados para dentro de um elemento HTML O comportamento padrão apenas permite que texto seja arrastado em regiões editáveis da página. Você pode especificar que um elemento e seus filhos podem se tornar editáveis incluindo o atributo contenteditable na tag de abertura do elemento. Você também pode tornar um documento inteiro editável definindo a propriedade designMode de objeto de documento como "on". Você pode suportar um comportamento alternativo de arrastar para dentro em uma página manipulando os eventos dragenter, dragover e drop para qualquer elemento que pode aceitar dados arrastados. Ativação de arrastar para dentro Para manipular o gesto de arrastar para dentro, você deve primeiro cancelar o comportamento padrão. Ouça os eventos dragenter e dragover em qualquer elemento HTML que deseja usar como destinos de soltar. Nos manipuladores desses eventos, chame o método preventDefault() do objeto de evento despachado. Cancelar o comportamento padrão permite que regiões não editáveis recebam uma ação de soltar. Obtenção de dados soltos Você pode acessar os dados soltos no manipulador para o evento ondrop: function doDrop(event){ droppedText = event.dataTransfer.getData("text/plain"); } Use o método dataTransfer.getData() para ler dados na área de transferência, transmitindo o tipo MIME do formato de dados a ler. Você pode descobrir que formatos de dados estão disponíveis usando a propriedade types do objeto dataTransfer. A matriz types contém a seqüência de caracteres de tipo MIME de cada formato disponível. Quando você cancela o comportamento padrão nos eventos dragenter ou dragover, você é responsável por inserir qualquer dado solto em seu próprio lugar no documento. Nenhuma API existe para converter uma posição do mouse em um ponto de inserção dentro de um elemento. Essa limitação pode dificultar a implementação de gestos de arrastar de tipo de inserção. Exemplo: Substituição do comportamento padrão de arrastar para dentro HTML Esse exemplo implementa um destino de soltar que exibe uma tabela mostrando cada formato de dados disponível no item solto. O comportamento padrão é usado para permitir que texto, links e imagens sejam arrastados no aplicativo. O exemplo substitui o comportamento padrão de arrastar para dentro para o elemento div que serve como o destino de soltar. A etapa principal para habilitar conteúdo não-editável para aceitar um gesto de arrastar para dentro é chamar o método preventDefault() do objeto de evento despachado para os eventos dragenter e dragover. Em resposta a um evento drop, o manipulador converte os dados transferidos em um elemento de linha HTML e insere a linha em uma tabela para exibição. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 146 Arrastar e soltar <html> <head> <title>Drag-and-drop</title> <script language="javascript" type="text/javascript" src="AIRAliases.js"></script> <script language="javascript"> function init(){ var target = document.getElementById('target'); target.addEventListener("dragenter", dragEnterOverHandler); target.addEventListener("dragover", dragEnterOverHandler); target.addEventListener("drop", dropHandler); var source = document.getElementById('source'); source.addEventListener("dragstart", dragStartHandler); source.addEventListener("dragend", dragEndHandler); emptyRow = document.getElementById("emptyTargetRow"); } function dragStartHandler(event){ event.dataTransfer.effectAllowed = "copy"; } function dragEndHandler(event){ air.trace(event.type + ": " + event.dataTransfer.dropEffect); } function dragEnterOverHandler(event){ event.preventDefault(); } var emptyRow; function dropHandler(event){ for(var prop in event){ air.trace(prop + " = " + event[prop]); } var row = document.createElement('tr'); row.innerHTML = "<td>" + event.dataTransfer.getData("text/plain") + "</td>" + "<td>" + event.dataTransfer.getData("text/html") + "</td>" + "<td>" + event.dataTransfer.getData("text/uri-list") + "</td>" + "<td>" + event.dataTransfer.getData("application/x-vnd.adobe.air.file-list") + "</td>"; var imageCell = document.createElement('td'); if((event.dataTransfer.types.toString()).search("image/x-vnd.adobe.air.bitmap") > 1){ imageCell.appendChild(event.dataTransfer.getData("image/xvnd.adobe.air.bitmap")); } row.appendChild(imageCell); var parent = emptyRow.parentNode; parent.insertBefore(row, emptyRow); } </script> </head> <body onLoad="init()" style="padding:5px"> <div> <h1>Source</h1> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 147 Arrastar e soltar <p>Items to drag:</p> <ul id="source"> <li>Plain text.</li> <li>HTML <b>formatted</b> text.</li> <li>A <a href="http://www.adobe.com">URL.</a></li> <li><img src="icons/AIRApp_16.png" alt="An image"/></li> <li style="-webkit-user-drag:none;"> Uses "-webkit-user-drag:none" style. </li> <li style="-webkit-user-select:none;"> Uses "-webkit-user-select:none" style. </li> </ul> </div> <div id="target" style="border-style:dashed;"> <h1 >Target</h1> <p>Drag items from the source list (or elsewhere).</p> <table id="displayTable" border="1"> <tr><th>Plain text</th><th>Html text</th><th>URL</th><th>File list</th><th>Bitmap Data</th></tr> <tr id="emptyTargetRow"><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</ td></tr> </table> </div> </div> </body> </html> Tratamento de arquivos soltos em caixas de proteção HTML de não-aplicativo O conteúdo de não-aplicativo não pode acessar os objetos File resultantes quando arquivos são arrastados em um aplicativo do AIR. Nem é possível transmitir um desses objetos File para conteúdo de aplicativo por uma ponte de caixa de proteção. (As propriedades do objeto devem ser acessadas durante a serialização.) No entanto, você pode ainda soltar arquivos no seu aplicativo ouvindo os eventos nativeDragDrop do AIR no objeto HTMLLoader. Normalmente, se um usuário solta um arquivo em um quadro que hospeda conteúdo de não-aplicativo, o evento de soltar não propaga do filho ao pai. No entanto, como os eventos despachados pelo HTMLLoader (que é o contêiner para todo o conteúdo HTML em um aplicativo do AIR) não são parte do fluxo de evento HTML, você pode ainda receber o evento de soltar em conteúdo de aplicativo. Para receber o evento para um arquivo solto, o documento pai adiciona um ouvinte de evento ao objeto HTMLLoader usando a referência fornecida por window.htmlLoader: window.htmlLoader.addEventListener("nativeDragDrop",function(event){ var filelist = event.clipboard.getData(air.ClipboardFormats.FILE_LIST_FORMAT); air.trace(filelist[0].url); }); O exemplo a seguir usa um documento pai que carrega uma página filha em uma caixa de proteção remota (http://localhost/). O pai ouve o evento nativeDragDrop no objeto HTMLLoader e marca a URL do arquivo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 148 Arrastar e soltar <html> <head> <title>Drag-and-drop in a remote sandbox</title> <script language="javascript" type="text/javascript" src="AIRAliases.js"></script> <script language="javascript"> window.htmlLoader.addEventListener("nativeDragDrop",function(event){ var filelist = event.clipboard.getData(air.ClipboardFormats.FILE_LIST_FORMAT); air.trace(filelist[0].url); }); </script> </head> <body> <iframe src="child.html" sandboxRoot="http://localhost/" documentRoot="app:/" frameBorder="0" width="100%" height="100%"> </iframe> </body> </html> O documento filho deve apresentar um destino de soltar válido impedindo que o método preventDefault() do objeto Event nos manipuladores de eventos dragenter e dragover HTML ou o evento de soltar nunca pode ocorrer. <html> <head> <title>Drag and drop target</title> <script language="javascript" type="text/javascript"> function preventDefault(event){ event.preventDefault(); } </script> </head> <body ondragenter="preventDefault(event)" ondragover="preventDefault(event)"> <div> <h1>Drop Files Here</h1> </div> </body> </html> Para obter mais informações, consulte “Programação em HTML e JavaScript” na página 233. 149 Capítulo 16: Copiar e colar Use as classes na API da área de transferência para copiar informações para e da área de transferência do sistema. Os formatos de dados que podem ser transferidos para ou de um aplicativo do Adobe® AIR™ incluem: • Bitmaps • Arquivos • Texto • Texto formatado em HTML • Dados em RTF • Strings URL • Objetos serializados • Referências a objetos (válido somente dentro do aplicativo originador) O Adobe Flash Player 10 adicionou a funcionalidade de copiar e colar que foi introduzida no AIR 1.0. Este capítulo discute a funcionalidade de copiar e colar única do Adobe AIR. Para obter detalhes sobre esta funcionalidade compartilhada, consulte Copiar e colar (no livro Programação do Adobe ActionScript 3.0. Informações online adicionais sobre copiar e colar Você pode encontrar mais informações sobre copiar e colar nessas fontes: Início rápido (Adobe AIR Developer Connection) • Suporte a arrastar e soltar e copiar e colar Referência de Linguagem • Clipboard • ClipboardFormats • ClipboardTransferMode Mais informações • Copiar e colar (no livro Programação do Adobe ActionScript 3.0) • Conexão de desenvolvedores do Adobe AIR para Flash (procurar 'AIR copiar e colar') Copiar e colar HTML O ambiente HTML fornece seu próprio conjunto de eventos e comportamento padrão para copiar e colar. Apenas códigos em execução na caixa de proteção do aplicativo podem acessar a área de transferência do sistema diretamente pelo objeto do AIR Clipboard.generalClipboard. Códigos JavaScript em uma caixa de proteção de não-aplicativo podem acessar a área de transferência pelo objeto de evento despachado em resposta a um dos eventos de copiar ou colar despachados por um elemento em um documento HTML. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 150 Copiar e colar Os eventos de copiar e colar incluem: copy, cut e paste. O objeto despachado para esses eventos fornece acesso à área de transferência pela propriedade clipboardData. Comportamento padrão Por padrão, o AIR copia itens selecionados em resposta ao comando de copiar, que pode ser gerado por um atalho do teclado ou um menu de contexto. Em regiões editáveis, o AIR recorta textos em resposta ao comando de recortar ou cola textos para o cursor ou seleção em resposta ao comando de colar. Para impedir o comportamento padrão, seu manipulador de eventos pode chamar o método preventDefault() do objeto de evento despachado. Uso da propriedade clipboardData do objeto de evento A propriedade clipboardData do objeto de evento despachado como um resultado de um dos eventos de copiar ou colar permite que você leia e escreva dados da área de transferência. Para escrever na área de transferência ao manipular um evento de copiar ou recortar, use o método setData() do objeto clipboardData, transmitindo os dados para copiar e o tipo MIME: function customCopy(event){ event.clipboardData.setData("text/plain", "A copied string."); } Para acessar os dados que estão sendo colados, você pode usar o método getData() do objeto clipboardData, transmitindo o tipo MIME do formato de dados. Os formatos disponíveis são relatados pela propriedade types. function customPaste(event){ var pastedData = event.clipboardData("text/plain"); } O método getData() e a propriedade types podem apenas ser acessados no objeto de evento despachado pelo evento paste. O exemplo a seguir ilustra como substituir o comportamento de copiar e colar padrão em uma página HTML. O manipulador de eventos copy coloca em itálico o texto copiado e o copia para a área de transferência como texto HTML. O manipulador de eventos cut copia os dados selecionados para a área de transferência e os remove do documento. O manipulador paste insere o conteúdo da área de transferência como HTML e aplica um estilo na inserção como texto em negrito. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 151 Copiar e colar <html> <head> <title>Copy and Paste</title> <script language="javascript" type="text/javascript"> function onCopy(event){ var selection = window.getSelection(); event.clipboardData.setData("text/html","<i>" + selection + "</i>"); event.preventDefault(); } function onCut(event){ var selection = window.getSelection(); event.clipboardData.setData("text/html","<i>" + selection + "</i>"); var range = selection.getRangeAt(0); range.extractContents(); event.preventDefault(); } function onPaste(event){ var insertion = document.createElement("b"); insertion.innerHTML = event.clipboardData.getData("text/html"); var selection = window.getSelection(); var range = selection.getRangeAt(0); range.insertNode(insertion); event.preventDefault(); } </script> </head> <body onCopy="onCopy(event)" onPaste="onPaste(event)" onCut="onCut(event)"> <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p> </body> </html> Comandos de menu e pressionamentos de tecla para copiar e colar A funcionalidade de copiar e colar é comumente disparada pelos comandos de menu e atalhos do teclado. No OS X, um menu de edição com os comandos de copiar e colar é criado automaticamente pelo sistema operacional, mas você deve adicionar ouvintes a esses comandos de menu para fazer a junção com suas próprias funções de copiar e colar. No Windows, você pode adicionar um menu de edição nativo a qualquer janela que use o cromo do sistema. (Você também pode criar menus não-nativos com Flex e ActionScript, ou, em conteúdo HTML, você pode usar DHTML, mas isso está além do escopo desta discussão.) Para disparar comandos de copiar e colar em resposta a atalhos do teclado, você pode atribuir teclas equivalentes aos itens de comando apropriados em um aplicativo nativo ou menu de janela ou você pode ouvir os pressionamentos de tecla diretamente. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 152 Copiar e colar Inicialização de uma operação de copiar ou colar com um comando de menu Para disparar uma operação de copiar ou colar com um comando de menu, você deve adicionar ouvintes ao evento select nos itens de menu que chamam as funções do seu manipulador. Quando a função do seu manipulador é chamada, você pode encontrar o objeto a ser copiado de ou colado usando a propriedade focus do estágio. Você pode então chamar o método apropriado do objeto focado (ou um método de fallback geral, se nenhum objeto possui foco) para realizar a lógica de copiar, recortar ou colar. Por exemplo, o seguinte manipulador de eventos copy verifica se o objeto focado é do tipo correto, nesse caso, uma classe chamada Scrap, e chama o método doCopy() do objeto. function copyCommand(event:Event):void{ if(NativeApplication.nativeApplication.activeWindow.stage.focus is Scrap){ Scrap(NativeApplication.nativeApplication.activeWindow.stage.focus).doCopy(); } else { NativeApplication.nativeApplication.copy(); } } Se copyCommand() no exemplo não reconhecer a classe do objeto focado, ele chamará o método copy() NativeApplication. O método copy() NativeApplication envia um comando de cópia interno para o objeto focado. Se o objeto for uma classe incorporada que implementa copiar e colar internamente, o objeto executará o comando. As classes Textfield e HTMLLoader são atualmente as únicas classes incorporadas. Outros objetos interativos despacharão o evento copy. Comandos similares estão disponíveis para recortar, colar, selecionar tudo e para TextArea apenas, limpar, desfazer e refazer. Em conteúdo HTML, o comportamento padrão de copiar e colar pode ser disparado usando os comandos de editar NativeApplication. O exemplo a seguir cria um menu de edição para um documento HTML editável: O exemplo anterior substitui o menu do aplicativo no Mac OS X, mas você também pode usar o menu Editar padrão encontrando os itens existentes e adicionando ouvintes de eventos a eles. Se você usar um menu de contexto para invocar um comando de copiar ou colar, poderá usar a propriedade contextMenuOwner do objeto ContextMenuEvent despachado quando o menu for aberto ou um item for selecionado para determinar qual objeto é o destino adequado do comando de copiar ou colar. Localização de itens de menu padrão no Mac OS X Para encontrar o menu de edição padrão e os itens de comando copiar, recortar e colar específicos no menu do aplicativo no Mac OS X, você pode pesquisar pela hierarquia do menu usando a propriedade label dos objetos NativeMenuItem. Por exemplo, a função a seguir adota um nome e encontra o item com o rótulo correspondente no menu: private function findItemByName(menu:NativeMenu, name:String, recurse:Boolean = false):NativeMenuItem{ var searchItem:NativeMenuItem = null; for each (var item:NativeMenuItem in menu.items){ if(item.label == name){ searchItem = item; break; } if((item.submenu != null) && recurse){ searchItem = findItemByName(item.submenu, name); } } return searchItem; } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 153 Copiar e colar Você pode definir o parâmetro recurse como true para incluir submenus na pesquisa ou false para incluir apenas o menu transmitido. Iniciando um comando de copiar ou colar com um pressionamento de tecla Se seu aplicativo usa a janela nativa ou menus do aplicativo para copiar e colar, você pode adicionar equivalentes de teclas aos itens de menu para implementar atalhos do teclado. Se seu aplicativo usa a janela nativa ou menus do aplicativo para copiar e colar, você pode adicionar equivalentes de teclas aos itens de menu para implementar atalhos do teclado. De outro modo, você pode ouvir por si só pressionamentos de teclas relevantes, como demonstrado no seguinte exemplo: private function init():void{ stage.addEventListener(KeyboardEvent.KEY_DOWN, keyListener); } private function keyListener(event:KeyboardEvent):void{ if(event.ctrlKey){ event.preventDefault(); switch(String.fromCharCode(event.charCode)){ case "c": NativeApplication.nativeApplication.copy(); break; case "x": NativeApplication.nativeApplication.cut(); break; case "v": NativeApplication.nativeApplication.paste(); break; case "a": NativeApplication.nativeApplication.selectAll(); break; case "z": NativeApplication.nativeApplication.undo(); break; case "y": NativeApplication.nativeApplication.redo(); break; } } } Em conteúdo HTML, os atalhos do teclado para comandos de copiar e colar são implementados por padrão. Não é possível capturar todos os pressionamentos de tecla comumente usados para copiar e colar usando um ouvinte de eventos de tecla. Se você precisar substituir o comportamento padrão, uma estratégia melhor seria ouvir os próprios eventos copy e paste. 154 Capítulo 17: Trabalhar com matrizes de bytes A classe ByteArray permite que você leia de e escreva para um fluxo de dados binário, que é essencialmente uma matriz de bytes. Essa classe fornece uma maneira de acessar dados no nível mais elementar. Como os dados do computador consistem em bytes, ou grupos de 8 bits, a capacidade de ler dados em bytes significa que você pode acessar dados para os quais classes e métodos de acesso não existem. A classe ByteArray permite que você analise qualquer fluxo de dados, de um bitmap a um fluxo de dados que viaje pela rede, no nível de byte. O método writeObject() permite que você escreva um objeto em AMF serializado para um ByteArray, enquanto o método readObject() permite que você leia um objeto serializado de um ByteArray para uma variável do tipo de dados original. Você pode serializar qualquer objeto, exceto objetos de exibição, que são aqueles que podem ser colocados na lista de exibição. Você também pode atribuir objetos serializados de volta às instâncias de classe personalizada se a classe personalizada estiver disponível para o tempo de execução. Após converter um objeto para AMF, você pode transferi-lo de modo eficiente por uma conexão de rede ou salvá-lo em um arquivo. O aplicativo de exemplo do Adobe® AIR™ descrito aqui lê um arquivo .zip como um exemplo de processar um fluxo de bytes; extraindo uma lista dos arquivos contidos no arquivo .zip e escrevendo-os na área de trabalho. Ler e escrever um ByteArray A classe ByteArray é parte do pacote flash.utils. Para criar um objeto ByteArray no ActionScript 3.0, importe a classe ByteArray e invoque o construtor, conforme exibido no seguinte exemplo: import flash.utils.ByteArray; var stream:ByteArray = new ByteArray(); Métodos ByteArray Qualquer fluxo de dados significativo é organizado em um formato que você pode analisar para encontrar as informações desejadas. Um registro em um simples arquivo de um funcionário, por exemplo, provavelmente incluiria um número de ID, um nome, um endereço, um número de telefone e assim por diante. Um arquivo de áudio MP3 contém uma marca ID3 que identifica o título, autor, álbum, data de publicação e gênero do arquivo que está sendo obtido por download. O formato permite que você saiba a ordem na qual esperar os dados no fluxo de dados. Ele permite que você leia o fluxo de bytes de modo inteligente. A classe ByteArray inclui vários métodos que facilitam ler de e escrever para um fluxo de dados. Alguns desses métodos incluem readBytes() e writeBytes(), readInt() e writeInt(), readFloat() e writeFloat(), readObject() e writeObject() e readUTFBytes() e writeUTFBytes(). Esses métodos permitem que você leia dados do fluxo de dados em variáveis de tipos de dados específicos e escreva de tipos de dados específicos diretamente para o fluxo de dados binário. Por exemplo, o código a seguir lê uma matriz simples de seqüências de caracteres e números de ponto flutuante e escreve cada elemento em um ByteArray. A organização da matriz permite que o código chame os métodos ByteArray apropriados (writeUTFBytes() e writeFloat()) para escrever os dados. O padrão de dados repetitivo possibilita ler a matriz com um loop. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 155 Trabalhar com matrizes de bytes // The following example reads a simple Array (groceries), made up of strings // and floating-point numbers, and writes it to a ByteArray. import flash.utils.ByteArray; // define the grocery list Array var groceries:Array = ["milk", 4.50, "soup", 1.79, "eggs", 3.19, "bread" , 2.35] // define the ByteArray var bytes:ByteArray = new ByteArray(); // for each item in the array for (var i:int = 0; i < groceries.length; i++) { bytes.writeUTFBytes(groceries[i++]); //write the string and position to the next item bytes.writeFloat(groceries[i]);// write the float trace("bytes.position is: " + bytes.position);//display the position in ByteArray } trace("bytes length is: " + bytes.length);// display the length A propriedade position A propriedade position armazena a posição atual do ponteiro que indexa ByteArray durante a leitura ou escrita. O valor inicial da propriedade position é 0 (zero), como exibido no seguinte código: var bytes:ByteArray = new ByteArray(); trace("bytes.position is initially: " + bytes.position); // 0 Quando você lê de ou escreve em um ByteArray, o método usado atualiza a propriedade position para apontar para o local imediatamente seguindo o último byte lido ou escrito. Por exemplo, o código a seguir escreve uma seqüência de caracteres em um ByteArray e, posteriormente, a propriedade position aponta para o byte imediatamente seguindo a seqüência de caracteres no ByteArray: var bytes:ByteArray = new ByteArray(); trace("bytes.position is initially: " + bytes.position); // 0 bytes.writeUTFBytes("Hello World!"); trace("bytes.position is now: " + bytes.position);// 12 Da mesma forma, uma operação de leitura incrementa a propriedade position pelo número de bytes lidos. var bytes:ByteArray = new ByteArray(); trace("bytes.position is initially: " + bytes.position); // 0 bytes.writeUTFBytes("Hello World!"); trace("bytes.position is now: " + bytes.position);// 12 bytes.position = 0; trace("The first 6 bytes are: " + (bytes.readUTFBytes(6)));//Hello trace("And the next 6 bytes are: " + (bytes.readUTFBytes(6)));// World! Observe que você pode definir a propriedade position para um local específico no ByteArray para ler ou escrever naquele deslocamento. As propriedades bytesAvailable e length As propriedades length e bytesAvailable dizem a você quanto tempo um ByteArray possui e quantos bytes permanecem nele da posição atual até o fim. O exemplo a seguir ilustra como você pode usar essas propriedades. O exemplo escreve uma seqüência de caracteres de texto para o ByteArray e, em seguida, lê um byte de cada vez do ByteArray até que ele encontre o caractere “a” ou o final (bytesAvailable <= 0). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 156 Trabalhar com matrizes de bytes var bytes:ByteArray = new ByteArray(); var text:String = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus etc."; bytes.writeUTFBytes(text); // write the text to the ByteArray trace("The length of the ByteArray is: " + bytes.length);// 70 bytes.position = 0; // reset position while (bytes.bytesAvailable > 0 && (bytes.readUTFBytes(1) != 'a')) { //read to letter a or end of bytes } if (bytes.position < bytes.bytesAvailable) { trace("Found the letter a; position is: " + bytes.position); // 23 trace("and the number of bytes available is: " + bytes.bytesAvailable);// 47 } A propriedade endian Os computadores podem diferir em como armazenam números de vários bytes, isto é, números que exigem mais de um 1 byte de memória para armazená-los. Um inteiro, por exemplo, pode levar 4 bytes, ou 32 bits, de memória. Alguns computadores armazenam o byte mais significativo do número primeiro, no endereço de memória mais baixo e outros armazenam o byte menos significativo primeiro. Esse atributo de um computador, ou de uma ordem de bytes, é conhecido como sendo big endian (byte mais significativo primeiro) ou little endian (byte menos significativo primeiro). Por exemplo, o número 0x31323334 seria armazenado da seguinte forma para ordem de bytes big endian e little endian, onde a0 representa o endereço de memória mais baixo dos 4 bytes e a3 representa o mais alto: Big Endian Big Endian Big Endian Big Endian a0 a1 a2 a3 31 32 33 34 Little Endian Little Endian Little Endian Little Endian a0 a1 a2 a3 34 33 32 31 A propriedade endian da classe ByteArray permite que você denote essa ordem de bytes para números de vários bytes que você esteja processando. Os valores aceitáveis para essa propriedade são "bigEndian" ou "littleEndian" e a classe Endian define as constantes BIG_ENDIAN e LITTLE_ENDIAN para definir a propriedade endian com essas seqüências de caracteres. Os métodos compress() e uncompress() O método compress() permite que você compacte um ByteArray de acordo com um algoritmo de compactação especificado como um parâmetro. O método uncompress() permite que você descompacte um ByteArray compactado de acordo com um algoritmo de compactação. Após chamar compress() e uncompress(), o comprimento da matriz de bytes é definida para o novo comprimento e a propriedade position é definida para o fim. A classe CompressionAlgorithm define constantes que você pode usar para especificar o algoritmo de compactação. O AIR suporta os algoritmos deflate e zlib. O algoritmo de compactação deflate é usado em vários formatos de compactação, tais como zlib, gzip e algumas implementações zip. O formato de dados compactado zlib é descrito em http://www.ietf.org/rfc/rfc1950.txt e o algoritmo de compactação deflate é descrito em http://www.ietf.org/rfc/rfc1951.txt. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 157 Trabalhar com matrizes de bytes O exemplo a seguir compacta um ByteArray chamado bytes usando o algoritmo deflate: bytes.compress(CompressionAlgorithm.DEFLATE); O exemplo a seguir descompacta um ByteArray compactado usando o algoritmo deflate: bytes.uncompress(CompressionAlgorithm.DEFLATE); Leitura e escrita de objetos Os métodos readObject() e writeObject() lêem um objeto de e escrevem um objeto para um ByteArray, codificado em AMF serializado. AMF é um protocolo de mensagens proprietário criado pela Adobe e usado por várias classes do ActionScript 3.0, incluindo Netstream, NetConnection, NetStream, LocalConnection e Shared Objects. Um marcador de tipo de um byte descreve o tipo dos dados codificados que segue. O AMF usa os 13 tipos de dados a seguir: value-type = undefined-marker | null-marker | false-marker | true-marker | integer-type | double-type | string-type | xml-doc-type | date-type | array-type | object-type | xml-type | byte-array-type Os dados codificados seguem o marcador de tipo, a menos que o marcador represente um único valor possível, como null ou true ou false, em cujo caso nada mais é codificado. Existem duas versões do AMF: AMF0 e AMF3. O AMF 0 suporta o envio de objetos complexos por referência e permite pontos de extremidade para restaurar as relações entre objetos. O AMF 3 melhora o AMF 0 enviando características de objetos e seqüências de caracteres por referência, além de referências de objetos, e suportando novos tipos de dados introduzidos no ActionScript 3.0. A propriedade ByteArray.objectEcoding especifica a versão do AMF usada para codificar os dados do objeto. A classe flash.net.ObjectEncoding define constantes para especificar a versão do AMF: ObjectEncoding.AMF0 e ObjectEncoding.AMF3. import flash.filesystem.*; import flash.utils.ByteArray; // Label component must be in Library import fl.controls.Label; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 158 Trabalhar com matrizes de bytes var bytes:ByteArray = new ByteArray(); var myLabel:Label = new Label(); myLabel.move(150, 150); myLabel.width = 200; addChild(myLabel); var myXML:XML = <order> <item id='1'> <menuName>burger</menuName> <price>3.95</price> </item> <item id='2'> <menuName>fries</menuName> <price>1.45</price> </item> </order> // Write XML object to ByteArray bytes.writeObject(myXML); bytes.position = 0;//reset position to beginning bytes.compress(CompressionAlgorithm.DEFLATE);// compress ByteArray outFile("order", bytes); myLabel.text = "Wrote order file to desktop!"; function outFile(fileName:String, data:ByteArray):void { var outFile:File = File.desktopDirectory; // dest folder is desktop outFile = outFile.resolvePath(fileName); // name of file to write var outStream:FileStream = new FileStream(); // open output file stream in WRITE mode outStream.open(outFile, FileMode.WRITE); // write out the file outStream.writeBytes(data, 0, data.length); // close it outStream.close(); } O método readObject() lê um objeto no AMF serializado de um ByteArray e o armazena em um objeto do tipo especificado. O exemplo a seguir lê o arquivo order da área de trabalho em um ByteArray (inBytes), o descompacta e chama readObject() para armazená-lo no objeto XML orderXML. O exemplo usa uma construção de loop for each() para adicionar cada nó a uma área de texto para exibição. O exemplo também exibe o valor da propriedade objectEncoding juntamente com um cabeçalho para o conteúdo do arquivo order. import flash.filesystem.*; import flash.utils.ByteArray; // TextArea component must be in Library import fl.controls.TextArea; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 159 Trabalhar com matrizes de bytes var inBytes:ByteArray = new ByteArray(); // define text area for displaying XML content var myTxt:TextArea = new TextArea(); myTxt.width = 550; myTxt.height = 400; addChild(myTxt); //display objectEncoding and file heading myTxt.text = "Object encoding is: " + inBytes.objectEncoding + "\n\n" + "order file: \n\n"; readFile("order", inBytes); inBytes.position = 0; // reset position to beginning inBytes.uncompress(CompressionAlgorithm.DEFLATE); inBytes.position = 0;//reset position to beginning // read XML Object var orderXML:XML = inBytes.readObject(); //for each node in orderXML for each(var child:XML in orderXML) { // append child node to text area myTxt.text += child + "\n"; } // read specified file into byte array function readFile(fileName:String, data:ByteArray) { var inFile:File = File.desktopDirectory; // source folder is desktop inFile = inFile.resolvePath(fileName); // name of file to read var inStream:FileStream = new FileStream(); inStream.open(inFile, FileMode.READ); inStream.readBytes(data, 0, data.length); inStream.close(); } Exemplo de ByteArray: leitura de um arquivo .zip Esse exemplo demonstra como ler um simples arquivo .zip contendo vários arquivos de diferentes tipos. Ele faz isso extraindo dados relevantes dos metadados para cada arquivo, descompactando cada arquivo em um ByteArray e escrevendo o arquivo na área de trabalho. A estrutura geral de um arquivo .zip é baseada na especificação de PKWARE Inc., mantida em http://www.pkware.com/documents/casestudies/APPNOTE.TXT. Primeiramente, está o cabeçalho de um arquivo e os dados do arquivo para o primeiro arquivo no arquivo .zip, seguido por um cabeçalho de arquivo e par de dados de arquivo para cada arquivo adicional. (A estrutura do cabeçalho do arquivo é descrita posteriormente.) Em seguida, o arquivo .zip inclui opcionalmente um registro de descritor de dados (normalmente quando o arquivo zip de saída foi criado na memória, e não salvo em um disco). Em seguida, estão vários elementos opcionais adicionais: cabeçalho de descriptografia do arquivo, registro de dados extra do arquivo, estrutura de diretório central, final Zip64 de registro de diretório central, final Zip64 de localizador de diretório central e final de registro de diretório central. O código nesse exemplo é escrito para analisar apenas arquivos zip que não contêm pastas e ele não espera registros de descritor de dados. Ele ignora todas as informações seguindo os dados do último arquivo. O formato do cabeçalho do arquivo para cada arquivo é o seguinte: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 160 Trabalhar com matrizes de bytes assinatura do cabeçalho do arquivo 4 bytes versão necessária 2 bytes sinalizador de bits de propósito geral 2 bytes método de compactação 2 bytes (8=DEFLATE; 0=UNCOMPRESSED) última hora de modificação do arquivo 2 bytes última data de modificação do arquivo 2 bytes crc-32 4 bytes tamanho compactado 4 bytes tamanho descompactado 4 bytes comprimento do nome do arquivo 2 bytes comprimento de campo extra 2 bytes nome de arquivo variável campo extra variável Seguindo o cabeçalho do arquivo estão os dados reais do arquivo, que podem ser compactados ou não, dependendo do sinalizador de método de compactação. O sinalizador é 0 (zero) se os dados do arquivo são descompactados, 8 se os dados são compactados usando o algoritmo DEFLATE ou outro valor para outros algoritmos de compactação. A interface de usuário para esse exemplo consiste de um rótulo e uma área de texto (taFiles). O aplicativo escreve as seguintes informações na área de texto para cada arquivo encontrado no arquivo .zip: o nome de arquivo, o tamanho compactado e o tamanho descompactado. O início do programa executa as seguintes tarefas: • Importa as classes necessárias import flash.filesystem.*; import flash.utils.ByteArray; import flash.events.Event; • Define a interface de usuário import fl.controls.*; //requires TextArea and Label components in the Library var taFiles = new TextArea(); var output = new Label(); taFiles.setSize(320, 150); taFiles.move(10, 30); output.move(10, 10); output.width = 150; output.text = "Contents of HelloAir.zip"; addChild(taFiles); addChild(output); • Define o ByteArray bytes var bytes:ByteArray = new ByteArray(); • Define variáveis para armazenar metadados do cabeçalho do arquivo DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 161 Trabalhar com matrizes de bytes // var var var var var var var var variables for reading fixed portion of file header fileName:String = new String(); flNameLength:uint; xfldLength:uint; offset:uint; compSize:uint; uncompSize:uint; compMethod:int; signature:int; • Define os objetos File (zfile) e FileStream (zStream) para representar o arquivo .zip e especifica o local do arquivo .zip a partir do qual os arquivos são extraídos — um arquivo chamado “HelloAIR.zip” no diretório da área de trabalho. // File variables for accessing .zip file var zfile:File = File.desktopDirectory.resolvePath("HelloAIR.zip"); var zStream:FileStream = new FileStream(); O programa começa abrindo o arquivo .zip em modo READ. zStream.open(zfile, FileMode.READ); Ele, em seguida, define a propriedade endian de bytes para LITTLE_ENDIAN para indicar que a ordem de bytes de campos numéricos possui o byte menos significativo primeiro. bytes.endian = Endian.LITTLE_ENDIAN; Em seguida, uma instrução while() começa um loop que continua até que a posição atual no fluxo do arquivo seja maior que ou igual ao tamanho do arquivo. while (zStream.position < zfile.size) { A primeira instrução dentro do loop lê os primeiros 30 bytes do fluxo do arquivo no ByteArray bytes. Os primeiros 30 bytes formam a parte de tamanho fixo do cabeçalho do primeiro arquivo. // read fixed metadata portion of local file header zStream.readBytes(bytes, 0, 30); Em seguida, o código lê um inteiro (signature) dos primeiros bytes do cabeçalho de 30 bytes. A definição do formato ZIP especifica que a assinatura para cada cabeçalho de arquivo é o valor hexadecimal 0x04034b50; se a assinatura for diferente, significa que o código se moveu além da parte do arquivo .zip e não existem mais arquivos para extrair. Nesse caso, o código sai do loop while imediatamente, em vez de esperar pelo final da matriz de bytes. bytes.position = 0; signature = bytes.readInt(); // if no longer reading data files, quit if (signature != 0x04034b50) { break; } A parte seguinte do código lê o byte do cabeçalho na posição de deslocamento 8 e armazena o valor na variável compMethod. Esse byte contém um valor que indica o método de compactação usado para compactar esse arquivo. Vários métodos de compactação são permitidos, mas, na prática, praticamente todos os arquivos .zip usam o algoritmo de compactação DEFLATE. Se o arquivo atual é compactado com a compactação DEFLATE, compMethod é 8; se o arquivo é descompactado, compMethod é 0. bytes.position = 8; compMethod = bytes.readByte(); // store compression method (8 == Deflate) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 162 Trabalhar com matrizes de bytes Seguindo os primeiros 30 bytes está uma parte de comprimento variável do cabeçalho que contém o nome do arquivo e, possivelmente, um campo extra. A variável offset armazena o tamanho dessa parte. O tamanho é calculado pela adição do comprimento do nome do arquivo e o comprimento do campo extra, lido do cabeçalho nos deslocamentos 26 e 28. offset = 0;// stores length of variable portion of metadata bytes.position = 26; // offset to file name length flNameLength = bytes.readShort();// store file name offset += flNameLength; // add length of file name bytes.position = 28;// offset to extra field length xfldLength = bytes.readShort(); offset += xfldLength;// add length of extra field Em seguida, o programa lê a parte de comprimento variável do cabeçalho do arquivo para o número de bytes armazenados na variável offset. // read variable length bytes between fixed-length header and compressed file data zStream.readBytes(bytes, 30, offset); O programa lê o nome do arquivo da parte de comprimento variável do cabeçalho e o exibe na área de texto, juntamente com os tamanhos compactados (zip) e descompactados (original) do arquivo. bytes.position = 30; fileName = bytes.readUTFBytes(flNameLength); // read file name taFiles.appendText(fileName + "\n"); // write file name to text area bytes.position = 18; compSize = bytes.readUnsignedInt(); // store size of compressed portion taFiles.appendText("\tCompressed size is: " + compSize + '\n'); bytes.position = 22; // offset to uncompressed size uncompSize = bytes.readUnsignedInt(); // store uncompressed size taFiles.appendText("\tUncompressed size is: " + uncompSize + '\n'); O exemplo lê o resto do arquivo do fluxo de arquivos em bytes para o comprimento especificado pelo tamanho compactado, substituindo o cabeçalho do arquivo nos primeiros 30 bytes. O tamanho compactado é preciso, mesmo se o arquivo não está compactado, porque, nesse caso, o tamanho compactado é igual ao tamanho descompactado do arquivo. // read compressed file to offset 0 of bytes; for uncompressed files // the compressed and uncompressed size is the same zStream.readBytes(bytes, 0, compSize); Em seguida, o exemplo descompacta o arquivo compactado e chama a função outfile() para escrevê-la no fluxo de arquivos de saída. Ele transmite a outfile() o nome do arquivo e a matriz de bytes que contém os dados do arquivo. if (compMethod == 8) // if file is compressed, uncompress { bytes.uncompress(CompressionAlgorithm.DEFLATE); } outFile(fileName, bytes); // call outFile() to write out the file A chave de fechamento indica o final do loop while e do código do aplicativo, exceto para o método outFile(). A execução volta ao início do loop while e continua processando os próximos bytes no arquivo .zip — extraindo outro arquivo ou finalizando o processamento do arquivo .zip se o último arquivo tiver sido processado. } // end of while loop DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 163 Trabalhar com matrizes de bytes A função outfile() abre um arquivo de saída no modo WRITE na área de trabalho, dando a ele o nome fornecido pelo parâmetro filename. Ela, em seguida, escreve os dados do arquivo do parâmetro data para o fluxo do arquivo de saída (outStream) e fecha o arquivo. function outFile(fileName:String, data:ByteArray):void { var outFile:File = File.desktopDirectory; // destination folder is desktop outFile = outFile.resolvePath(fileName); // name of file to write var outStream:FileStream = new FileStream(); // open output file stream in WRITE mode outStream.open(outFile, FileMode.WRITE); // write out the file outStream.writeBytes(data, 0, data.length); // close it outStream.close(); } 164 Capítulo 18: Trabalhar com bancos de dados SQL locais O Adobe AIR permite criar e trabalhar com bancos de dados SQL locais. O tempo de execução inclui um mecanismo de banco de dados SQL com suporte para muitos recursos SQL padrão através do sistema de banco de dados de códigofonte aberto SQLite. Um banco de dados SQL local pode ser usado para armazenar dados locais persistentes. Por exemplo, ele pode ser usado para dados de aplicativo, configurações de usuários de aplicativo, documentos ou qualquer outro tipo de dados que você desejar que o aplicativo salve localmente. Mais informações on-line sobre bancos de dados SQL locais Você encontra mais informações sobre como trabalhar com bancos de dados SQL locais nestas fontes: Início rápido (Adobe AIR Developer Connection) • Trabalhar assincronamente com um banco de dados SQL local • Trabalhar sincronamente com um banco de dados SQL local • Usar banco de dados criptografado Referência de linguagem • SQLCollationType • SQLColumnNameStyle • SQLColumnSchema • SQLConnection • SQLError • SQLErrorEvent • SQLErrorOperation • SQLEvent • SQLIndexSchema • SQLMode • SQLResult • SQLSchema • SQLSchemaResult • SQLStatement • SQLTableSchema • SQLTransactionLockType • SQLTriggerSchema DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 165 Trabalhar com bancos de dados SQL locais • SQLUpdateEvent • SQLViewSchema Artigos e amostras do Adobe Developer Connection • Adobe AIR Developer Connection para Flash (procure ‘AIR SQL’) Sobre bancos de dados SQL locais O Adobe AIR inclui um mecanismo de banco de dados relacional baseado em SQL que é executado no tempo de execução, com dados armazenados localmente em arquivos de banco de dados no computador em que o aplicativo do AIR é executado (no disco rígido do computador, por exemplo). Como a execução do banco de dados ocorre localmente, da mesma forma que o armazenamento dos arquivos de dados, um banco de dados pode ser usado por um aplicativo do AIR independentemente de haver uma conexão de rede disponível. Por isso, o mecanismo de banco de dados SQL local do tempo de execução é conveniente para armazenar dados de aplicativo locais persistentes, principalmente se você tem experiência em SQL e bancos de dados relacionais. Usos de bancos de dados SQL locais A funcionalidade de banco de dados SQL local do AIR pode ser utilizada para qualquer finalidade quando você quiser armazenar dados de aplicativo no computador local de um usuário. O Adobe AIR inclui diversos mecanismos para armazenar dados localmente, e cada um deles tem suas próprias vantagens. Veja abaixo alguns dos usos possíveis de um banco de dados SQL local no aplicativo do AIR: • No caso de um aplicativo orientado a dados (um catálogo de endereços, por exemplo), é possível usar um banco de dados para armazenar os principais dados de aplicativo. • No caso de um aplicativo orientado a documento, em que os usuários criam documentos para salvá-los e possivelmente compartilhá-los, cada documento pode ser salvo como um arquivo de banco de dados em um local designado pelo usuário. (Observe, no entanto, que a menos que o banco de dados seja criptografado, qualquer aplicativo do AIR poderia abrir o arquivo do banco de dados. A criptografia é recomendada para documentos potencialmente confidenciais.) • No caso de um aplicativo com reconhecimento de rede, é possível usar um banco de dados para armazenar um cache local de dados de aplicativo ou para armazenar dados temporariamente quando não há uma conexão de rede disponível. Você pode criar um mecanismo para sincronizar o banco de dados local com o armazenamento de dados da rede. • No caso de qualquer aplicativo, um banco de dados pode ser usado para armazenar configurações de aplicativo de um usuário, como opções ou informações do aplicativo (por exemplo, o tamanho e a posição das janelas). Sobre bancos de dados AIR e arquivos de banco de dados Um banco de dados SQL local do Adobe AIR é armazenado como um único arquivo no sistema de arquivos do computador. O tempo de execução inclui o mecanismo de banco de dados SQL que gerencia a criação e a estruturação de arquivos de banco de dados, bem como a manipulação e a recuperação de dados de um arquivo de banco de dados. O tempo de execução não especifica como ou onde os dados de banco de dados são armazenados no sistema de arquivos; cada banco de dados é armazenado por completo em um único arquivo. Você especifica o local no sistema de arquivos em que o arquivo do banco de dados deve ser armazenado. Um único aplicativo do AIR pode acessar um ou vários bancos de dados separados (isto é, arquivos de banco de dados separados). Como o tempo de execução armazena cada banco de dados como um único arquivo no sistema de arquivos, você pode localizar o seu banco de DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 166 Trabalhar com bancos de dados SQL locais dados quando necessário pelo design das restrições do sistema operacional quanto ao acesso a aplicativos e arquivos. Cada usuário pode ter um arquivo de banco de dados à parte para seus dados específicos, ou um arquivo de banco de dados pode ser acessado por todos os usuários do aplicativo em um único computador para dados compartilhados. Como os dados estão armazenados localmente em um único computador, eles não são compartilhados automaticamente em diferentes computadores. O mecanismo de banco de dados SQL local não tem um recurso que permita executar instruções SQL em um banco de dados remoto ou baseado em servidor. Sobre bancos de dados relacionais Um banco de dados relacional consiste em um mecanismo para armazenar (e recuperar) dados em um computador. Os dados são organizados em tabelas: as linhas representam registros ou itens, e as colunas (também chamadas de “campos”) dividem cada registro em valores individuais. Por exemplo, um aplicativo de catálogo de endereços pode conter uma tabela chamada “amigos”. Cada linha da tabela representa um único amigo armazenado no banco de dados. As colunas da tabela representam dados como nome, sobrenome, data de nascimento e assim por diante. Para cada linha de amigo na tabela, o banco de dados armazena um valor em separado para cada coluna. Os bancos de dados relacionais têm a finalidade de armazenar dados complexos, em que um item é associado ou relacionado a itens de outro tipo. Em um banco de dados relacional, qualquer dado que tem um relacionamento umpara-muitos — em que um único registro pode estar relacionado a vários registros de um tipo diferente — deve ser dividido entre diferentes tabelas. Por exemplo, suponha que você queira que o aplicativo de catálogo de endereços armazene vários números de telefone de cada amigo; isto é um relacionamento um-para-muitos. A tabela “amigos” contém todas as informações pessoais de cada amigo. Uma tabela à parte chamada “números de telefone” contém todos os números de telefone de todos os amigos. Além de armazenar os dados de amigos e os números de telefone, cada tabela precisa de dados para controlar os relacionamentos entre as duas tabelas — a fim de comparar registros de amigo individuais com seus números de telefone. Esses dados são chamados de chave primária, um identificador exclusivo que diferencia cada linha de uma tabela das demais linhas dessa tabela. A chave primária pode ser uma “chave natural”, ou seja, um dos itens de dados que diferencia cada registro de uma tabela naturalmente. Na tabela “amigos”, se você souber que nenhum dos seus amigos tem a mesma data de aniversário, poderá usar a coluna de data de nascimento como a chave primária (uma chave natural) dessa tabela. Se não houver uma chave natural, crie uma coluna de chave primária em separado, como “id de amigo”: um valor artificial que o aplicativo usa para diferenciar entre as linhas. Utilizando uma chave primária, você pode configurar relacionamentos entre várias tabelas. Por exemplo, suponha que na tabela "amigos" exista uma coluna chamada "id de amigo", que contém um número exclusivo para cada linha (cada amigo). A tabela “números de telefone” relacionada pode ser estruturada com duas colunas: uma com o “id de amigo” do amigo a quem pertence o número de telefone e outra com o número de telefone propriamente dito. Assim, independentemente de quantos números de telefones um só amigo tiver, todos poderão ser armazenados na tabela “números de telefone” e vinculados ao amigo relacionado através da chave primária “id de amigo”. Quando uma chave primária de uma tabela é usada em uma tabela relacionada para especificar a conexão entre os registros, o valor contido na tabela é chamado de chave externa. Diferentemente de muitos bancos de dados, o mecanismo de banco de dados local do AIR não permite criar restrições de chave externa, que são restrições que automaticamente verificam se um valor de chave externa inserido ou atualizado tem uma linha correspondente na tabela de chave primária. Todavia, os relacionamentos de chave externa são uma parte importante da estrutura de um banco de dados relacional, e as chaves externas devem ser usadas quando você cria relacionamentos entre as tabelas do banco de dados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 167 Trabalhar com bancos de dados SQL locais Sobre a SQL A SQL (linguagem de consulta estruturada) é usada com bancos de dados relacionais para manipular e recuperar dados. A SQL é uma linguagem descritiva e não de procedimento. Em vez de dar ao computador instruções sobre como recuperar dados, uma instrução SQL descreve o conjunto de dados desejado. O mecanismo de banco de dados determina como recuperar esses dados. A linguagem SQL foi padronizada pelo ANSI (American National Standards Institute). O banco de dados SQL local do Adobe AIR suporta a maior parte do padrão SQL-92. Para obter descrições específicas da linguagem SQL suportada no Adobe AIR, consulte o apêndice “Suporte a SQL em bancos de dados locais“ na Referência dos componentes e da linguagem do ActionScript 3.0. Sobre classes de banco de dados SQL Para trabalhar com bancos de dados SQL locais no ActionScript 3.0, você deve usar ocorrências destas classes do pacote flash.data: Classe Descrição flash.data.SQLConnection Oferece um modo de criar e abrir bancos de dados (arquivos de banco de dados), bem como métodos para executar operações no nível de banco de dados e controlar transações de banco de dados. flash.data.SQLStatement Representa uma única instrução SQL (uma única consulta ou comando) que é executada em um banco de dados, incluindo a definição do texto da instrução e a configuração dos valores de parâmetro. flash.data.SQLResult Oferece um modo de obter informações sobre execução de uma instrução ou os resultados dela, como as linhas de resultado de uma instrução SELECT, o número de linhas afetadas por uma instrução UPDATE ou DELETE e assim por diante. Para obter informações de esquema que descrevam a estrutura de um banco de dados, use estas classes do pacote flash.data: Classe Descrição flash.data.SQLSchemaResult Funciona como um contêiner de resultados do esquema de banco de dados gerados pela chamada do método SQLConnection.loadSchema(). flash.data.SQLTableSchema Fornece informações que descrevem uma única tabela de um banco de dados. flash.data.SQLViewSchema Fornece informações que descrevem uma única visualização de um banco de dados. flash.data.SQLIndexSchema Fornece informações que descrevem uma única coluna de uma tabela ou visualização de um banco de dados. flash.data.SQLTriggerSchem a Fornece informações que descrevem um único disparador de um banco de dados. Outras classes do pacote flash.data fornecem constantes que são utilizadas com as classes SQLConnection e SQLColumnSchema: Classe Descrição flash.data.SQLMode Define um conjunto de constantes que representam os valores possíveis para o parâmetro openMode dos métodos SQLConnection.open() e SQLConnection.openAsync(). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 168 Trabalhar com bancos de dados SQL locais Classe Descrição flash.data.SQLColumnNameStyle Define um conjunto de constantes que representam os valores possíveis para a propriedade SQLConnection.columnNameStyle. flash.data.SQLTransactionLockType Define um conjunto de constantes que representam os valores possíveis para o parâmetro de opção do método SQLConnection.begin(). flash.data.SQLCollationType Define um conjunto de constantes que representam os valores possíveis para a propriedade SQLColumnSchema.defaultCollationType e o parâmetro defaultCollationType do construtor SQLColumnSchema(). Além disso, as seguintes classes do pacote flash.events representam os eventos (e as constantes de suporte) que você utiliza: Classe Descrição flash.data.SQLEvent Define os eventos que uma ocorrência de SQLConnection ou SQLStatement despacha quando alguma de suas operações é executada com êxito. Cada operação tem uma constante de tipo de evento associada definida na classe SQLEvent. flash.data.SQLErrorEvent Define o evento que uma ocorrência de SQLConnection ou SQLStatement despacha quando alguma de suas operações resulta em erro. flash.data.SQLUpdateEvent Define o evento que uma ocorrência de SQLConnection despacha quando dados de tabela de um dos bancos de dados conectados são alterados como resultado da execução de uma instrução SQL INSERT, UPDATE ou DELETE. Para finalizar, as seguintes classes do pacote flash.errors fornecem informações sobre erros de operação do banco de dados: Classe Descrição flash.data.SQLError Fornece informações sobre um erro de funcionamento do banco de dados, incluindo a operação que foi tentada e a causa da falha. flash.data.SQLErrorEvent Define um conjunto de constantes que representam os valores possíveis para a propriedade operation da classe SQLError, que indica a operação de banco de dados que resultou em erro. Sobre modos de execução síncrona e assíncrona Quando você cria código para trabalhar com um banco de dados SQL local, especifica que a execução das operações de banco de dados ocorra de um destes dois modos de execução: modo de execução assíncrona ou síncrona. Em geral, os exemplos de código mostram como executar cada operação das duas maneiras, para que você possa usar o exemplo mais adequado às suas necessidades. No modo de execução assíncrona, você dá uma instrução ao tempo de execução, que despacha um evento quando a operação solicitada é concluída ou quando falha. Primeiro você instrui o mecanismo de banco de dados a executar uma operação. O mecanismo de banco de dados trabalha em segundo plano enquanto o aplicativo continua a executar. Por último, quando a operação é concluída (ou se falha), o mecanismo de banco de dados despacha um evento. O seu código, disparado pelo evento, executa operações subseqüentes. Esta abordagem tem uma vantagem significativa: o tempo de execução realiza as operações de banco de dados em segundo plano enquanto o código do aplicativo principal continua en execução. Se a operação de banco de dados demorar muito tempo, o aplicativo continuará executando. O mais importante é que o usuário pode continuar a interagir com ele sem que a tela congele. Entretanto, o código de operação assíncrona pode ser mais complexo de criar do que outro código. Essa complexidade geralmente ocorre quando várias operações dependentes devem ser divididas entre diversos métodos de ouvinte de evento. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 169 Trabalhar com bancos de dados SQL locais Em termos conceituais, é mais fácil codificar operações como uma seqüência simples de etapas (um conjunto de operações síncronas) e não como um conjunto de operações divididas em vários métodos de ouvinte de evento. Além das operações de banco de dados assíncronas, o Adobe AIR também permite executar operações de banco de dados de maneira síncrona. No modo de execução síncrona, as operações não são executadas em segundo plano. Elas ocorrem na mesma seqüência de execução que todos os outros códigos de aplicativo. Você instrui o mecanismo de banco de dados a executar uma operação. Em seguida, o código pausa nesse ponto enquanto o mecanismo de banco de dados faz o seu trabalho. Quando a operação é concluída, a execução prossegue com a próxima linha do código que você criou. O fato de as operações serem executadas de maneira assíncrona ou síncrona é definido no nível de SQLConnection. Usando uma única conexão de banco de dados, você não consegue executar algumas operações ou instruções em modo síncrono e outras em modo assíncrono. Você especifica se uma classe SQLConnection opera no modo de execução síncrono ou assíncrono chamando um método SQLConnection para abrir o banco de dados. Se você chamar SQLConnection.open(), a conexão funcionará no modo de execução síncrona; se você chamar SQLConnection.openAsync(), ela funcionará no modo de execução assíncrona. Uma vez que uma ocorrência de SQLConnection é conectada a um banco de dados usando open() ou openAsync(), ela é fixada ao modo de execução síncrona ou assíncrona, a menos que você feche e reabra a conexão com o banco de dados. Cada modo de execução tem suas vantagens. Apesar da semelhança entre a maioria dos aspectos de cada modo, existem algumas diferenças das quais você deve se lembrar quando trabalhar neles. Para obter mais informações sobre estes tópicos, e sugestões de como trabalhar em cada modo, consulte “Uso de operações de banco de dados síncronas e assíncronas” na página 190. Criação e modificação de um banco de dados Para que o seu aplicativo adicione ou recupere dados, deve haver um banco de dados com tabelas definidas nele que possam ser acessadas pelo aplicativo. Descrevemos aqui as tarefas de criação de um banco de dados e da estrutura de dados de um banco de dados. Embora usadas com menos freqüência do que a inserção e a recuperação de dados, estas tarefas são necessárias para a maioria dos aplicativos. Criação de um banco de dados Para criar um arquivo de banco de dados, primeiro você deve criar uma ocorrência de SQLConnection. Chame o método open() correspondente para abri-la no modo de execução síncrona ou o método openAsync() para abri-la no modo de execução assíncrona. Os métodos open() e openAsync() são usados para abrir uma conexão com um banco de dados. Se você passar uma ocorrência de File que se refira a um local de arquivo não existente para o parâmetro reference (o primeiro parâmetro), o método open() ou openAsync() criará um arquivo de banco de dados no local do arquivo e abrirá uma conexão com o banco de dados recém-criado. Independentemente de você chamar o método open() ou openAsync() para criar um banco de dados, o nome do arquivo do banco de dados poderá ser qualquer nome de arquivo válido com qualquer extensão de nome de arquivo. Se você chamar o método open() ou openAsync() com null para o parâmetro reference, será criado um novo banco de dados na memória e não um arquivo de banco de dados no disco. A listagem de código a seguir mostra o processo de criação de um arquivo de banco de dados (um novo banco de dados) usando o modo de execução assíncrona. Nesse caso, o arquivo de banco de dados é salvo no diretório de armazenamento do aplicativo com o nome de arquivo “DBSample.db”: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 170 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); conn.openAsync(dbFile); function openHandler(event:SQLEvent):void { trace("the database was created successfully"); } function errorHandler(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } Para executar operações de maneira síncrona, quando abrir uma conexão de banco de dados com a ocorrência de SQLConnection, chame o método open(). O seguinte exemplo mostra como criar e abrir uma ocorrência de SQLConnection que execute suas operações de maneira síncrona: import flash.data.SQLConnection; import flash.errors.SQLError; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); try { conn.open(dbFile); trace("the database was created successfully"); } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } Criação de tabelas de banco de dados Criar uma tabela em um banco de dados envolve executar uma instrução SQL nesse banco de dados usando o mesmo processo seguido para executar uma instrução SQL, como SELECT, INSERT, entre outras. Para criar uma tabela, use uma instrução CREATE TABLE, que inclui definições de colunas e restrições para a nova tabela. Para obter mais informações sobre como executar instruções SQL, consulte “Trabalhar com instruções SQL” na página 173. O exemplo a seguir demonstra como criar uma tabela chamada “employees” em um arquivo de banco de dados existente usando o modo de execução assíncrona. Observe que este código presume que há uma ocorrência de SQLConnection denominada conn já instanciada e conectada a um banco de dados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 171 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLStatement; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; // ... create and open the SQLConnection instance named conn ... var createStmt:SQLStatement = new SQLStatement(); createStmt.sqlConnection = conn; var sql:String = "CREATE TABLE IF NOT EXISTS employees (" + " empId INTEGER PRIMARY KEY AUTOINCREMENT, " + " firstName TEXT, " + " lastName TEXT, " + " salary NUMERIC CHECK (salary > 0)" + ")"; createStmt.text = sql; createStmt.addEventListener(SQLEvent.RESULT, createResult); createStmt.addEventListener(SQLErrorEvent.ERROR, createError); createStmt.execute(); function createResult(event:SQLEvent):void { trace("Table created"); } function createError(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } O exemplo a seguir demonstra como criar uma tabela chamada “employees” em um arquivo de banco de dados existente usando o modo de execução síncrona. Observe que este código presume que há uma ocorrência de SQLConnection denominada conn já instanciada e conectada a um banco de dados. import flash.data.SQLConnection; import flash.data.SQLStatement; import flash.errors.SQLError; // ... create and open the SQLConnection instance named conn ... var createStmt:SQLStatement = new SQLStatement(); createStmt.sqlConnection = conn; var sql:String = "CREATE TABLE IF NOT EXISTS employees (" + " empId INTEGER PRIMARY KEY AUTOINCREMENT, " + " firstName TEXT, " + " lastName TEXT, " + " salary NUMERIC CHECK (salary > 0)" + ")"; createStmt.text = sql; try { createStmt.execute(); trace("Table created"); } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 172 Trabalhar com bancos de dados SQL locais Manipulação de dados de um banco de dados SQL Existem algumas tarefas comuns que você executa ao trabalhar com bancos de dados SQL locais. Essas tarefas incluem conectar-se a um banco de dados, adicionar dados a tabelas e recuperar dados de tabelas em um banco de dados. Também há vários problemas dos quais você deve estar ciente quando executa essas tarefas, como trabalhar com tipos de dados e tratar de erros. Além disso, há diversas tarefas de banco de dados que envolvem coisas com as quais você lidará menos freqüentemente, mas que deverá fazer para poder executar essas tarefas mais comuns. Por exemplo, para poder se conectar a um banco de dados e recuperar dados de uma tabela, você terá de criar o banco de dados e a estrutura de tabelas nele. Essas tarefas de configuração inicial menos freqüentes são discutidas em “Criação e modificação de um banco de dados” na página 169. Você pode optar por executar operações de banco de dados assincronamente, o que significa que o mecanismo de banco de dados é executado em segundo plano e despacha um evento para notificar o usuário quando a operação é bem-sucedida ou quando falha. Também é possível executar estas operações de forma síncrona. Nesse caso, as operações de banco de dados são executadas uma após a outra, e o aplicativo inteiro (inclusive atualizações da tela) espera até que as operações sejam concluídas para poder executar outro código. Os exemplos desta seção demonstram como executar as operações de modo assíncrono e síncrono. Para obter mais informações sobre como trabalhar no modo de execução assíncrona ou síncrona, consulte “Uso de operações de banco de dados síncronas e assíncronas” na página 190. Conexão com um banco de dados Para que você possa executar qualquer operação de banco de dados, primeiro abra uma conexão com o arquivo de banco de dados. Uma ocorrência de SQLConnection é usada para representar uma conexão com um ou mais bancos de dados. O primeiro banco de dados conectado usando uma ocorrência de SQLConnection é chamado de banco de dados "principal". Esse banco de dados é conectado através do método open() (para o modo de execução síncrona) ou do método openAsync() (para o modo de execução assíncrona). Se você abrir um banco de dados usando a operação openAsync() assíncrona, registre-se para o evento open da ocorrência de SQLConnection para saber quando a operação openAsync() for concluída. Registre-se para o evento error da ocorrência de SQLConnection para determinar se a operação falhou. O exemplo a seguir mostra como abrir um arquivo de banco de dados existente para execução assíncrona. O arquivo de banco de dados chama-se “DBSample.db” e está localizado no diretório de armazenamento de aplicativo do usuário. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 173 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLMode; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); conn.openAsync(dbFile, SQLMode.UPDATE); function openHandler(event:SQLEvent):void { trace("the database opened successfully"); } function errorHandler(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } O exemplo a seguir mostra como abrir um arquivo de banco de dados existente para execução síncrona. O arquivo de banco de dados chama-se “DBSample.db” e está localizado no diretório de armazenamento de aplicativo do usuário. import flash.data.SQLConnection; import flash.data.SQLMode; import flash.errors.SQLError; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); try { conn.open(dbFile, SQLMode.UPDATE); trace("the database opened successfully"); } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } Observe que, na chamada do método openAsync() no exemplo de operação assíncrona e na chamada do método open() no exemplo de operação síncrona, o segundo argumento é a constante SQLMode.UPDATE. Especificar SQLMode.UPDATE para o segundo parâmetro (openMode) faz com que o tempo de execução despache um erro se o arquivo especificado não existe. Caso você passe SQLMode.CREATE para o parâmetro openMode (ou caso deixe o parâmetro openMode como off), o tempo de execução tentará criar um arquivo de banco de dados se o arquivo especificado não existir. No entanto, se o arquivo existir, será aberto, o que é o mesmo que usar SQLMode.Update. Também é possível especificar SQLMode.READ para o parâmetro openMode para abrir um banco de dados existente em modo somente leitura. Nesse caso, os dados podem ser recuperados do banco de dados, mas não é possível adicionar, excluir ou alterar nenhum dado. Trabalhar com instruções SQL Uma instrução SQL individual (consulta ou comando) é representada no tempo de execução como um objeto SQLStatement. Siga estas etapas para criar e executar uma instrução SQL: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 174 Trabalhar com bancos de dados SQL locais Crie uma ocorrência de SQLStatement. O objeto SQLStatement representa a instrução SQL no seu aplicativo. var selectData:SQLStatement = new SQLStatement(); Especifique em que banco de dados a consulta é executada. Para isso, defina a propriedade sqlConnection do objeto SQLStatement como a ocorrência de SQLConnection que está conectada ao banco de dados desejado. // A SQLConnection named "conn" has been created previously selectData.sqlConnection = conn; Especifique a instrução SQL propriamente dita. Crie o texto da instrução como String e o atribua à propriedade text da ocorrência de SQLStatement. selectData.text = "SELECT col1, col2 FROM my_table WHERE col1 = :param1"; Defina funções para trabalhar com o resultado da operação de execução (somente no modo de execução assíncrona). Use o método addEventListener() para registrar funções como ouvintes para os eventos result e error da ocorrência de SQLStatement. // using listener methods and addEventListener(); selectData.addEventListener(SQLEvent.RESULT, resultHandler); selectData.addEventListener(SQLErrorEvent.ERROR, errorHandler); function resultHandler(event:SQLEvent):void { // do something after the statement execution succeeds } function errorHandler(event:SQLErrorEvent):void { // do something after the statement execution fails } Se preferir, você pode especificar métodos de ouvinte usando um objeto Responder. Nesse caso, crie a ocorrência de Responder e vincule os métodos de ouvinte a ela. // using a Responder (flash.net.Responder) var selectResponder = new Responder(onResult, onError); function onResult(result:SQLResult):void { // do something after the statement execution succeeds } function onError(error:SQLError):void { // do something after the statement execution fails } Se o texto da instrução incluir definições de parâmetro, atribua valores para esses parâmetros. Para atribuir valores de parâmetro, use a propriedade de matriz associativa parameters da ocorrência de SQLStatement. selectData.parameters[":param1"] = 25; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 175 Trabalhar com bancos de dados SQL locais Execute a instrução SQL. Chame o método execute() da ocorrência de SQLStatement. // using synchronous execution mode // or listener methods in asynchronous execution mode selectData.execute(); Além disso, se você estiver usando um Responder em vez de ouvintes de evento no modo de execução assíncrona, passe a ocorrência de Responder para o método execute(). // using a Responder in asynchronous execution mode selectData.execute(-1, selectResponder); Para obter exemplos específicos que demonstrem estas etapas, consulte os seguintes tópicos: “Recuperação de dados de um banco de dados” na página 177 “Inserção de dados” na página 183 “Alteração ou exclusão de dados” na página 185 Uso de parâmetros em instruções Um parâmetro de instrução SQL permite criar uma instrução SQL reutilizável. Quando você usa parâmetros de instrução, os valores na instrução podem mudar (como os que estão sendo adicionados a uma instrução INSERT), mas o texto básico dela permanece inalterado. Conseqüentemente, usar parâmetros oferece o benefício do desempenho, além de facilitar a codificação de um aplicativo. Noções básicas sobre parâmetros de instrução É freqüente um aplicativo usar uma única instrução SQL várias vezes, com uma leve variação. Por exemplo, considere um aplicativo de controle de inventário no qual um usuário pode adicionar itens de inventário ao banco de dados. O código do aplicativo que adiciona um item de inventário ao banco de dados executa uma instrução SQL INSERT que, na verdade, adiciona os dados ao banco de dados. No entanto, cada vez que a instrução é executada, há uma leve variação. Especificamente, os valores reais inseridos na tabela são diferentes porque são específicos do item de inventário que está sendo adicionado. Em casos nos quais você tem uma instrução SQL que é usada várias vezes com diferentes valores na instrução, a melhor abordagem é utilizar uma instrução SQL que inclua parâmetros em vez de valores literais no texto SQL. Um parâmetro consiste em um alocador de espaço no texto da instrução que é substituído por um valor real sempre que a instrução é executada. Para usar parâmetros em uma instrução SQL, crie a ocorrência de SQLStatement como de costume. No caso da instrução SQL propriamente dita atribuída à propriedade text, use alocadores de espaço de parâmetro em vez de valores literais. Em seguida, defina o valor para cada parâmetro definindo o valor de um elemento na propriedade parameters da ocorrência de SQLStatement. A propriedade parameters é uma matriz associativa, por isso você define um valor em particular usando a seguinte sintaxe: statement.parameters[parameter_identifier] = value; parameter_identifier é uma string (se você está usando um parâmetro nomeado) ou um índice de inteiro (se está usando um parâmetro sem nome). Uso de parâmetros nomeados Um parâmetro pode ser um parâmetro nomeado. Um parâmetro nomeado tem um nome específico que o banco de dados utiliza para comparar o valor do parâmetro à localização do alocador de espaço no texto da instrução. Um nome de parâmetro consiste no caractere “:” ou “@” seguido de um nome, como nestes exemplos: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 176 Trabalhar com bancos de dados SQL locais :itemName @firstName A seguinte listagem de código demonstra o uso de parâmetros nomeados: var sql:String = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (:name, :productCode)"; var addItemStmt:SQLStatement = new SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[":name"] = "Item name"; addItemStmt.parameters[":productCode"] = "12345"; addItemStmt.execute(); Uso de parâmetros sem nome Como alternativa ao uso de parâmetros nomeados, também é possível utilizar parâmetros sem nome. Para usar um parâmetro sem nome, indique um parâmetro em uma instrução SQL usando um caractere “?” . Cada parâmetro recebe um índice numérico conforme a ordem dos parâmetros da instrução, começando com o índice 0 para o primeiro parâmetro. Este exemplo demonstra uma versão do exemplo anterior usando parâmetros sem nome: var sql:String = "INSERT INTO inventoryItems (name, productCode)" + "VALUES (?, ?)"; var addItemStmt:SQLStatement = new SQLStatement(); addItemStmt.sqlConnection = conn; addItemStmt.text = sql; // set parameter values addItemStmt.parameters[0] = "Item name"; addItemStmt.parameters[1] = "12345"; addItemStmt.execute(); Benefícios do uso de parâmetros O uso de parâmetros em uma instrução SQL proporciona vários benefícios: Melhor desempenho Uma ocorrência de SQLStatement que usa parâmetros é executada com mais eficiência se comparada a uma que cria o texto SQL dinamicamente sempre que é executada. A melhoria do desempenho ocorre porque a instrução é preparada uma única vez e pode ser executada várias vezes usando-se diferentes valores de parâmetro, sem a necessidade de recompilar a instrução SQL. Digitação de dados explícita Os parâmetros são usados para permitir a substituição de valores digitados que são desconhecidos no momento em que a instrução SQL é construída. O uso de parâmetros é o único modo de garantir a classe de armazenamento para um valor passado ao banco de dados. Quando parâmetros não são usados, o tempo de execução tenta converter todos os valores de sua representação em texto para uma classe de armazenamento com base na afinidade de tipo da coluna associada. Para obter mais informações sobre classes de armazenamento e afinidade de coluna, consulte a seção “Suporte ao tipo de dados“ no apêndice “Suporte a SQL em bancos de dados locais“ da Referência dos componentes e da linguagem do ActionScript 3.0. Mais segurança O uso de parâmetros ajuda a impedir uma técnica mal-intencionada conhecida como ataque de injeção SQL. Em um ataque de injeção SQL, um usuário insere o código SQL em um local acessível ao usuário (por exemplo, um campo de entrada de dados). Se o código do aplicativo construir uma instrução SQL concatenando diretamente a entrada do usuário no texto SQL, o código SQL inserido pelo usuário será executado em relação ao banco de dados. A lista a seguir mostra um exemplo de concatenação da entrada do usuário no texto SQL. Não use esta técnica: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 177 Trabalhar com bancos de dados SQL locais // assume the variables "username" and "password" // contain user-entered data var sql:String = "SELECT userId " + "FROM users " + "WHERE username = '" + username + "' " + " AND password = '" + password + "'"; var statement:SQLStatement = new SQLStatement(); statement.text = sql; O uso de parâmetros de instrução em vez de concatenar valores inseridos pelo usuário no texto de uma instrução impede o ataque de injeção SQL. A injeção de SQL não ocorre porque os valores de parâmetro são tratados explicitamente como valores substituídos, em vez de se tornarem parte do texto da instrução literal. Esta é uma alternativa recomendável à listagem anterior: // assume the variables "username" and "password" // contain user-entered data var sql:String = "SELECT userId " + "FROM users " + "WHERE username = :username " + " AND password = :password"; var statement:SQLStatement = new SQLStatement(); statement.text = sql; // set parameter values statement.parameters[":username"] = username; statement.parameters[":password"] = password; Recuperação de dados de um banco de dados A recuperação de dados de um banco de dados envolve duas etapas. Primeiro, você executa uma instrução SQL SELECT que descreve o conjunto de dados desejado do banco de dados. Em seguida, você acessa os dados recuperados e os exibe ou manipula conforme exigido pelo aplicativo. Execução de uma instrução SELECT Para recuperar dados existentes de um banco de dados, use uma ocorrência de SQLStatement. Atribua a instrução SQL SELECT adequada à propriedade text da ocorrência e, depois, chame o método execute() correspondente. Para obter detalhes da sintaxe da instrução SELECT, consulte o apêndice “Suporte a SQL em bancos de dados locais" da Referência dos componentes e da linguagem do ActionScript 3.0. O exemplo abaixo mostra como executar uma instrução SELECT para recuperar dados de uma tabela chamada “products” usando o modo de execução assíncrona: var selectStmt:SQLStatement = new SQLStatement(); // A SQLConnection named "conn" has been created previously selectStmt.sqlConnection = conn; selectStmt.text = "SELECT itemId, itemName, price FROM products"; // The resultHandler and errorHandler are listener methods are // described in a subsequent code listing selectStmt.addEventListener(SQLEvent.RESULT, resultHandler); selectStmt.addEventListener(SQLErrorEvent.ERROR, errorHandler); selectStmt.execute(); O exemplo abaixo mostra como executar uma instrução SELECT para recuperar dados de uma tabela chamada “products” usando o modo de execução assíncrona: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 178 Trabalhar com bancos de dados SQL locais var selectStmt:SQLStatement = new SQLStatement(); // A SQLConnection named "conn" has been created previously selectStmt.sqlConnection = conn; selectStmt.text = "SELECT itemId, itemName, price FROM products"; // This try..catch block is fleshed out in // a subsequent code listing try { selectStmt.execute(); // accessing the data is shown in a subsequent code listing } catch (error:SQLError) { // error handling is shown in a subsequent code listing } No modo de execução assíncrona, quando a execução da instrução é concluída, a ocorrência de SQLStatement despacha um evento result (SQLEvent.RESULT) que indica que a instrução foi executada com sucesso. Como alternativa, se um objeto Responder for passado como argumento na chamada de execute(), a função do manipulador resultante do objeto Responder será chamada. No modo de execução síncrona, a execução pausa até que a operação execute() seja concluída e, em seguida, prossegue com a próxima linha de código. Acesso a dados de resultados da instrução SELECT Uma vez concluída a execução da instrução SELECT, a próxima etapa é acessar os dados que foram recuperados. Cada linha de dados do conjunto de resultados de SELECT torna-se uma ocorrência de Object. Esse objeto tem propriedades cujos nomes correspondem aos nomes de coluna do conjunto de resultados. As propriedades contêm os valores das colunas do conjunto de resultados. Por exemplo, suponha que uma instrução SELECT especifique um conjunto de resultados com três colunas chamadas “itemId”, “itemName” e “price”. Para cada linha do conjunto de resultados, é criada uma ocorrência de Object com propriedades chamadas itemId, itemName e price. Essas propriedades contêm os valores das respectivas colunas. A listagem de código a seguir dá continuidade à listagem de código anterior para recuperar dados no modo de execução assíncrona. Ela mostra como acessar os dados recuperados no método do ouvinte de evento resultante. function resultHandler(event:SQLEvent):void { var result:SQLResult = selectStmt.getResult(); var numResults:int = result.data.length; for (var i:int = 0; i < numResults; i++) { var row:Object = result.data[i]; var output:String = "itemId: " + row.itemId; output += "; itemName: " + row.itemName; output += "; price: " + row.price; trace(output); } } function errorHandler(event:SQLErrorEvent):void { // Information about the error is available in the // event.error property, which is an instance of // the SQLError class. } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 179 Trabalhar com bancos de dados SQL locais A listagem de código a seguir expande a listagem de código anterior para recuperar dados no modo de execução síncrona. Ela expande o bloco try..catch do exemplo anterior de execução síncrona, mostrando como acessar os dados recuperados. try { selectStmt.execute(); var result:SQLResult = selectStmt.getResult(); var numResults:int = result.data.length; for (var i:int = 0; i < numResults; i++) { var row:Object = result.data[i]; var output:String = "itemId: " + row.itemId; output += "; itemName: " + row.itemName; output += "; price: " + row.price; trace(output); } } catch (error:SQLError) { // Information about the error is available in the // error variable, which is an instance of // the SQLError class. } Quando as listagens de código anteriores são exibidas, os objetos resultantes estão contidos em uma matriz disponível como a propriedade data de uma ocorrência de SQLResult. Se você estiver usando a execução assíncrona com um ouvinte de evento, para recuperar essa ocorrência de SQLResult, terá de chamar o método getResult() da ocorrência de SQLStatement. Se você especificar um argumento Responder na chamada de execute(), a ocorrência de SQLResult será passada para a função do manipulador resultante como um argumento. No modo de execução síncrona, você chama o método getResult() da ocorrência de SQLStatement a qualquer momento depois da chamada do método execute(). Em ambos os casos, depois que você tiver o objeto SQLResult, poderá acessar as linhas de resultado utilizando a propriedade de matriz data. A listagem de código a seguir define uma ocorrência de SQLStatement cujo texto é uma instrução SELECT. A instrução recupera linhas que contêm os valores de coluna firstName e lastName de todas as linhas de uma tabela denominada employees. Este exemplo utiliza o modo de execução assíncrona. Quando a execução é concluída, o método selectResult() é chamado, e as linhas de dados resultantes são acessadas usando SQLStatement.getResult() e exibidas usando o método trace(). Observe que esta listagem presume que existe uma ocorrência de SQLConnection denominada conn que já foi instanciada e já está conectada ao banco de dados. Ela também presume que a tabela “employees” já foi criada e preenchida com dados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 180 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLResult; import flash.data.SQLStatement; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; // ... create and open the SQLConnection instance named conn ... // create the SQL statement var selectStmt:SQLStatement = new SQLStatement(); selectStmt.sqlConnection = conn; // define the SQL text var sql:String = "SELECT firstName, lastName " + "FROM employees"; selectStmt.text = sql; // register listeners for the result and error events selectStmt.addEventListener(SQLEvent.RESULT, selectResult); selectStmt.addEventListener(SQLErrorEvent.ERROR, selectError); // execute the statement selectStmt.execute(); function selectResult(event:SQLEvent):void { // access the result data var result:SQLResult = selectStmt.getResult(); var numRows:int = result.data.length; for (var i:int = 0; i < numRows; i++) { var output:String = ""; for (var columnName:String in result.data[i]) { output += columnName + ": " + result.data[i][columnName] + "; "; } trace("row[" + i.toString() + "]\t", output); } } function selectError(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } A listagem de código a seguir demonstra as mesmas técnicas que a anterior, mas usa o modo de execução síncrona. O exemplo define uma ocorrência de SQLStatement cujo texto é uma instrução SELECT. A instrução recupera linhas que contêm os valores de coluna firstName e lastName de todas as linhas de uma tabela denominada employees. As linhas de dados resultantes são acessadas usando SQLStatement.getResult() e exibidas usando o método trace(). Observe que esta listagem presume que existe uma ocorrência de SQLConnection denominada conn que já foi instanciada e já está conectada ao banco de dados. Ela também presume que a tabela “employees” já foi criada e preenchida com dados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 181 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLResult; import flash.data.SQLStatement; import flash.errors.SQLError; // ... create and open the SQLConnection instance named conn ... // create the SQL statement var selectStmt:SQLStatement = new SQLStatement(); selectStmt.sqlConnection = conn; // define the SQL text var sql:String = "SELECT firstName, lastName " + "FROM employees"; selectStmt.text = sql; try { // execute the statement selectStmt.execute(); // access the result data var result:SQLResult = selectStmt.getResult(); var numRows:int = result.data.length; for (var i:int = 0; i < numRows; i++) { var output:String = ""; for (var columnName:String in result.data[i]) { output += columnName + ": " + result.data[i][columnName] + "; "; } trace("row[" + i.toString() + "]\t", output); } } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } Definição do tipo de dados dos dados resultantes de SELECT Por padrão, cada linha retornada por uma instrução SELECT é criada como uma ocorrência de Object com propriedades nomeadas para os nomes de coluna do conjunto de resultados e com o valor de cada coluna como o valor da propriedade associada. Porém, antes de executar uma instrução SQL SELECT, você pode definir a propriedade itemClass da ocorrência de SQLStatement para uma classe. Quando é definida a propriedade itemClass, cada linha retornada pela instrução SELECT é criada como ocorrência da classe designada. O tempo de execução atribui valores de coluna resultantes a valores de propriedade comparando os nomes de coluna do conjunto de resultados de SELECT com os nomes das propriedades da classe itemClass. Qualquer classe designada como um valor da propriedade itemClass deve ter um construtor que não exija parâmetros. Além disso, a classe deve ter uma única propriedade para cada coluna retornada pela instrução SELECT. Será considerado um erro se uma coluna da lista SELECT não tiver um nome de propriedade correspondente na classe itemClass. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 182 Trabalhar com bancos de dados SQL locais Recuperação dos resultados de SELECT em partes Por padrão, a execução de uma instrução SELECT recupera todas as linhas do conjunto de resultados de uma só vez. Uma vez concluída a instrução, geralmente você processa os dados recuperados de alguma forma; por exemplo, criando objetos ou exibindo os dados na tela. Se a instrução retornar muitas linhas, processar todos os dados de uma só vez pode exigir bastante do computador, o que, por sua vez, faz com que a interface do usuário não se redesenhe. É possível melhorar o desempenho percebido do aplicativo instruindo o tempo de execução a retornar um determinado número de linhas de resultado por vez. Isso faz com que os dados resultantes iniciais sejam retornados mais rapidamente. Isso também permite dividir as linhas de resultados em conjuntos, para que a interface de usuário seja atualizada depois do processamento de cada conjunto de linhas. Só é prático usar esta técnica no modo de execução assíncrona. Para recuperar os resultados de SELECT em partes, especifique um valor para o primeiro parâmetro do método SQLStatement.execute() (o parâmetro prefetch). O parâmetro prefetch indica o número de linhas a serem recuperadas na primeira vez que a instrução é executada. Quando chamar o método execute() de uma ocorrência de SQLStatement, especifique um valor de parâmetro prefetch e somente essas linhas serão recuperadas: var stmt:SQLStatement = new SQLStatement(); stmt.sqlConnection = conn; stmt.text = "SELECT ..."; stmt.addEventListener(SQLEvent.RESULT, selectResult); stmt.execute(20); // only the first 20 rows (or fewer) are returned A instrução despacha o evento result, indicando que o primeiro conjunto de linhas de resultado está disponível. A propriedade data da ocorrência de SQLResult resultante contém as linhas de dados, e sua propriedade complete indica se existem mais linhas de resultado a serem recuperadas. Para recuperar linhas de resultados adicionais, chame o método next() da ocorrência de SQLStatement. Assim como o método execute(), o primeiro parâmetro do método next() é utilizado para indicar quantas linhas deverão ser recuperadas na próxima vez que o evento result for despachado. function selectResult(event:SQLEvent):void { var result:SQLResult = stmt.getResult(); if (result.data != null) { // ... loop through the rows or perform other processing ... if (!result.complete) { stmt.next(20); // retrieve the next 20 rows } else { stmt.removeEventListener(SQLEvent.RESULT, selectResult); } } } SQLStatement despacha um evento result sempre que o método next() retorna um conjunto subseqüente de linhas de resultado. Conseqüentemente, a mesma função de ouvinte pode ser usada para continuar processando os resultados (de chamadas de next()) até que todas as linhas sejam recuperadas. Para obter mais informações, consulte as descrições dos métodos SQLStatement.execute() (a descrição do parâmetro prefetch) e SQLStatement.next() na referência de linguagem. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 183 Trabalhar com bancos de dados SQL locais Inserção de dados A recuperação de dados de um banco de dados envolve executar uma instrução SQL INSERT. Depois de concluída a execução da instrução, você poderá acessar a chave primária da linha recém-inserida se a chave tiver sido gerada pelo banco de dados. Execução de uma instrução INSERT Para adicionar dados a uma tabela de um banco de dados, crie e execute uma ocorrência de SQLStatement cujo texto é uma instrução SQL INSERT. O exemplo a seguir usa uma ocorrência de SQLStatement para adicionar uma linha de dados à tabela employees já existente. Este exemplo demonstra como inserir dados usando o modo de execução assíncrona. Observe que esta listagem presume que existe uma ocorrência de SQLConnection denominada conn que já foi instanciada e já está conectada a um banco de dados. Ela também presume que a tabela “employees” já foi criada. import flash.data.SQLConnection; import flash.data.SQLResult; import flash.data.SQLStatement; import flash.events.SQLErrorEvent; import flash.events.SQLEvent; // ... create and open the SQLConnection instance named conn ... // create the SQL statement var insertStmt:SQLStatement = new SQLStatement(); insertStmt.sqlConnection = conn; // define the SQL text var sql:String = "INSERT INTO employees (firstName, lastName, salary) " + "VALUES ('Bob', 'Smith', 8000)"; insertStmt.text = sql; // register listeners for the result and failure (status) events insertStmt.addEventListener(SQLEvent.RESULT, insertResult); insertStmt.addEventListener(SQLErrorEvent.ERROR, insertError); // execute the statement insertStmt.execute(); function insertResult(event:SQLEvent):void { trace("INSERT statement succeeded"); } function insertError(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } O exemplo a seguir adiciona uma linha de dados à tabela employees já existente usando o modo de execução síncrona. Observe que esta listagem presume que existe uma ocorrência de SQLConnection denominada conn que já foi instanciada e já está conectada a um banco de dados. Ela também presume que a tabela “employees” já foi criada. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 184 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLResult; import flash.data.SQLStatement; import flash.errors.SQLError; // ... create and open the SQLConnection instance named conn ... // create the SQL statement var insertStmt:SQLStatement = new SQLStatement(); insertStmt.sqlConnection = conn; // define the SQL text var sql:String = "INSERT INTO employees (firstName, lastName, salary) " + "VALUES ('Bob', 'Smith', 8000)"; insertStmt.text = sql; try { // execute the statement insertStmt.execute(); trace("INSERT statement succeeded"); } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } Recuperação de uma chave primária gerada pelo banco de dados de uma linha inserida Com freqüência, depois de inserir uma linha de dados a uma tabela, o código precisa ser informado sobre uma chave primária gerada pelo banco de dados ou o valor do identificador da linha recém-inserida. Por exemplo, depois de inserir uma linha em uma tabela, você deve adicionar linhas a uma tabela relacionada. Nesse caso, convém inserir o valor da chave primária como chave externa na tabela relacionada. A chave primária de uma linha recém-inserida pode ser recuperada usando o objeto SQLResult gerado pela execução da instrução. É o mesmo objeto usado para acessar dados de resultado depois que uma instrução SELECT é executada. Assim como ocorre com qualquer instrução SQL, quando a execução de uma instrução INSERT é concluída, o tempo de execução cria uma ocorrência de SQLResult. Para acessar a ocorrência de SQLResult, chame o método getResult() do objeto SQLStatement se você estiver usando um ouvinte de evento ou o modo de execução síncrona. Se preferir, caso esteja usando o modo de execução assíncrona e passe uma ocorrência de Responder para a chamada de execute(), a ocorrência de SQLResult será passada como argumento para a função do manipulador resultante. Seja como for, a ocorrência de SQLResult tem uma propriedade, chamada lastInsertRowID, que contém o identificador de linha da linha inserida mais recentemente se a instrução SQL executada é uma instrução INSERT. Este exemplo mostra como acessar a chave primária de uma linha inserida no modo de execução assíncrona: insertStmt.text = "INSERT INTO ..."; insertStmt.addEventListener(SQLEvent.RESULT, resultHandler); insertStmt.execute(); function resultHandler(event:SQLEvent):void { // get the primary key var result:SQLResult = insertStmt.getResult(); var primaryKey:Number = result.lastInsertRowID; // do something with the primary key } Este exemplo mostra como acessar a chave primária de uma linha inserida no modo de execução síncrona: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 185 Trabalhar com bancos de dados SQL locais insertStmt.text = "INSERT INTO ..."; try { insertStmt.execute(); // get the primary key var result:SQLResult = insertStmt.getResult(); var primaryKey:Number = result.lastInsertRowID; // do something with the primary key } catch (error:SQLError) { // respond to the error } Observe que o identificador de linha pode ou não ser o valor da coluna designada como a coluna de chave primária na definição de tabela, de acordo com a seguinte regra: • Se a tabela está definida com uma coluna de chave primária cuja afinidade (tipo de dados da coluna) é INTEGER, a propriedade lastInsertRowID contém o valor inserido nessa linha (ou o valor gerado pelo tempo de execução, no caso de uma coluna AUTOINCREMENT). • Se a tabela está definida com várias colunas de chave primária (uma chave composta) ou com uma única coluna de chave primária cuja afinidade não é INTEGER, o banco de dados gera um valor de identificador de coluna para a linha em segundo plano. Esse valor gerado é o valor da propriedade lastInsertRowID. • O valor é sempre o identificador de linha da linha inserida mais recentemente. Se uma instrução INSERT faz com que seja acionado um disparador que, por sua vez, insere uma linha, a propriedade lastInsertRowID contém o identificador de linha da última linha inserida pelo disparador em vez da linha criada pela instrução INSERT. Conseqüentemente, se você quiser ter uma coluna de chave primária definida explicitamente cujo valor fica disponível após um comando INSERT através da propriedade SQLResult.lastInsertRowID, a coluna deverá ser definida como uma coluna INTEGER PRIMARY KEY. Porém, mesmo que a tabela não inclua uma coluna INTEGER PRIMARY KEY explícita, será igualmente aceitável usar o identificador de linha gerado pelo banco de dados como uma chave primária para a sua tabela com o intuito de definir relacionamentos com tabelas relacionadas. O valor da coluna do identificador de linha fica disponível em qualquer instrução SQL através do uso de um dos nomes de coluna especiais ROWID, _ROWID_ ou OID. É possível criar uma coluna de chave externa em uma tabela relacionada e usar o valor do identificador de linha como o valor da coluna de chave externa, assim como você faria com uma coluna INTEGER PRIMARY KEY declarada explicitamente. Nesse sentido, se estiver usando uma chave primária arbitrária em vez de uma chave natural, e desde que não se importe que o tempo de execução gere o valor da chave primária para você, faz pouca diferença se você usa uma coluna INTEGER PRIMARY KEY ou o identificador de linha gerado pelo sistema como a chave primária de uma tabela para definir um relacionamento de chave externa entre duas tabelas. Para obter mais informações sobre chaves primárias e identificadores de linha gerados, consulte as seções “CREATE TABLE” e “Expressões” no apêndice “Suporte a SQL em bancos de dados locais” da Referência dos componentes e da linguagem do ActionScript 3.0. Alteração ou exclusão de dados O processo para executar outras operações de manipulação de dados é idêntico ao seguido para executar uma instrução SQL SELECT ou INSERT. Basta substituir uma instrução SQL diferente na propriedade text da ocorrência de SQLStatement: • Para alterar dados existentes em uma tabela, use uma instrução UPDATE. • Para excluir uma ou mais linhas de dados de uma tabela, use uma instrução DELETE. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 186 Trabalhar com bancos de dados SQL locais Para obter a descrição dessas instruções, consulte o apêndice “Suporte a SQL em bancos de dados locais” da Referência dos componentes e da linguagem do ActionScript 3.0. Trabalhar com vários bancos de dados Use o método SQLConnection.attach() para abrir uma conexão com um banco de dados adicional em uma ocorrência de SQLConnection que já tem um banco de dados aberto. Dê um nome ao banco de dados anexado usando o parâmetro de nome na chamada do método attach(). Ao escrever instruções para manipular esse banco de dados, você poderá usar esse nome em um prefixo (no formato nome-do-bancodedados.nome-da-tabela) para qualificar qualquer nome de tabela em suas instruções SQL, indicando ao tempo de execução que a tabela pode ser encontrada no banco de dados nomeado. É possível executar uma única instrução SQL que inclua tabelas de vários bancos de dados conectados à mesma ocorrência de SQLConnection. Se uma transação for criada na ocorrência de SQLConnection, ela será aplicada a todas as instruções SQL executadas usando a ocorrência de SQLConnection. Isso é válido independentemente do banco de dados anexado no qual a instrução é executada. Se preferir, você também pode criar várias ocorrências de SQLConnection em um aplicativo, cada uma delas conectada a um ou a vários bancos de dados. Contudo, se você usar várias conexões com o mesmo banco de dados, lembre-se de que uma transação de banco de dados não é compartilhada entre ocorrências de SQLConnection. Conseqüentemente, se você se conectar ao mesmo arquivo de banco de dados usando várias ocorrências de SQLConnection, não poderá contar que as alterações de dados em ambas as conexões sejam aplicadas da maneira esperada. Por exemplo, se duas instruções UPDATE ou DELETE forem executadas no mesmo banco de dados através de diferentes ocorrências de SQLConnection e acontecer um erro de aplicativo depois de executada uma operação, os dados do banco de dados poderão ficar em um estado intermediário irreversível que talvez afete a integridade do banco de dados (e, conseqüentemente, o aplicativo). Tratamento de erros de banco de dados Em geral, o tratamento de erros de banco de dados é parecido com o de outros erros de tempo de execução. Você deve criar um código preparado para eventuais erros e para responder a eles em vez de deixar que o tempo de execução faça isso. De um modo geral, os erros de banco de dados possíveis dividem-se em três categorias: erros de conexão, de sintaxe SQL e de restrição. Erro de conexão A maioria dos erros de banco de dados são de conexão, e eles podem ocorrer durante qualquer operação. Embora haja estratégias para prevenir erros de conexão, raramente existe uma forma simples de se recuperar tranqüilamente de um erro desse tipo se o banco de dados é um componente crítico do seu aplicativo. A maior parte dos erros de conexão tem a ver com a maneira como o tempo de execução interage com o sistema operacional, o sistema de arquivos e o arquivo de banco de dados. Por exemplo, ocorre um erro de conexão quando o usuário não tem permissão para criar um arquivo de banco de dados em um determinado local do sistema de arquivos. As seguintes estratégias ajudam a prevenir erros de conexão: Utilize arquivos de banco de dados específicos do usuário Em vez de usar um único arquivo de banco de dados para todos os usuários que utilizam um mesmo computador, dê a cada usuário seu próprio arquivo de banco de dados. O arquivo deve estar localizado em um diretório associado com a conta do usuário. Por exemplo, ele pode estar no diretório de armazenamento do aplicativo, na pasta de documentos do usuário, na área de trabalho dele, e assim por diante. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 187 Trabalhar com bancos de dados SQL locais Leve em consideração diferentes tipos de usuário Teste seu aplicativo com diferentes tipos de contas de usuário em diferentes sistemas operacionais. Não suponha que o usuário tem permissão de administrador no computador. Também não presuma que quem instalou o aplicativo é o usuário que o está executando. Leve em consideração localizações de arquivo diferentes Se você permitir que um usuário especifique onde salvar um arquivo de banco de dados ou selecione um arquivo a ser aberto, considere as possíveis localizações de arquivo que os usuários podem usar. Além disso, considere a possibilidade de definir limites quanto aos locais em que os usuários podem armazenar (ou abrir) arquivos de banco de dados. Por exemplo, você só deve permitir que eles abram arquivos existentes no local de armazenamento de suas contas de usuário. Se acontecer um erro de conexão, é mais provável que ele ocorra na primeira tentativa de criar ou abrir o banco de dados. Isso significa que o usuário não consegue fazer nenhuma operação relacionada a banco de dados no aplicativo. Para certos tipos de erros, como erros de permissão ou somente leitura, uma técnica de recuperação possível consiste em copiar o arquivo de banco de dados para outro local. O aplicativo pode copiar o arquivo de banco de dados para outro local, em que o usuário tenha permissão para criar e gravar em arquivos, e pode usar esse local. Erros de sintaxe Um erro de sintaxe ocorre quando uma instrução SQL está formada incorretamente e o aplicativo tenta executá-la. Como as instruções SQL de banco de dados local são criadas como strings, não é possível fazer a verificação da sintaxe SQL durante a compilação. Todas as instruções SQL devem ser executadas para verificar sua sintaxe. Adote as seguintes estratégias para evitar erros de sintaxe SQL: Teste todas as instruções SQL integralmente Se possível, enquanto desenvolve o aplicativo, teste as instruções SQL separadamente antes de codificá-las como texto de instrução no código do aplicativo. Além disso, use uma abordagem de teste do código, como teste de unidade, para criar um conjunto de testes que aplique todas as opções e variações possíveis no código. Use parâmetros de instrução e evite concatenar (gerar dinamicamente) o SQL Usar parâmetros, e evitar instruções SQL criadas dinamicamente, significa que o mesmo texto de instrução SQL é usado sempre que uma instrução é executada. Conseqüentemente, é bem mais fácil testar suas instruções e limitar a variação possível. Se você tiver de gerar uma instrução SQL dinamicamente, use o mínimo possível de partes dinâmicas na instrução. Além disso, seja cauteloso ao validar qualquer entrada de usuário para se certificar de que ela não causará erros de sintaxe. Para se recuperar de um erro de sintaxe, um aplicativo precisa de uma lógica complexa que permita examinar uma instrução SQL e corrigir sua sintaxe. Se forem seguidas as diretrizes acima para evitar erros de sintaxe, o código conseguirá identificar qualquer possível origem de tempo de execução de erros de sintaxe SQL (como entradas de usuário utilizadas em uma instrução). Para se recuperar de um erro de sintaxe, oriente o usuário. Indique o que deve ser corrigido para que a instrução seja executada corretamente. Erros de restrição Erros de restrição ocorrem quando uma instrução INSERT ou UPDATE tenta adicionar dados a uma coluna. O erro acontece se os novos dados violam uma das restrições definidas para a tabela ou coluna. O conjunto de restrições possíveis inclui: Restrição exclusiva Indica que, entre todas as linhas de uma tabela, não pode existir valores duplicados em uma coluna. Como alternativa, quando várias colunas são combinadas em uma restrição exclusiva, a combinação de valores dessas colunas não deve ser duplicada. Em outras palavras, em termos da(s) coluna(s) exclusiva(s) especificada(s), cada linha deve ser distinta. Restrição de chave primária Em termos dos dados permitidos e não permitidos por uma restrição, a restrição de chave primária é idêntica a uma restrição exclusiva. Restrição não nula Especifica que uma única coluna não pode armazenar um valor NULL e, conseqüentemente, que em cada linha essa coluna deve ter um valor. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 188 Trabalhar com bancos de dados SQL locais Restrição de verificação Permite especificar uma restrição arbitrária em uma ou mais tabelas. Uma restrição de verificação comum é uma regra que define que o valor de uma coluna deve estar dentro de certos limites (por exemplo, que o valor de uma coluna numérica deve ser maior que 0). Outro tipo de restrição de verificação comum especifica relacionamentos entre valores de coluna (por exemplo, que o valor de uma coluna deve ser diferente do de outra coluna na mesma linha). Restrição de tipo de dados (afinidade de coluna) O tempo de execução impõe o tipo de dados de valores de colunas, e ocorre um erro se é feita uma tentativa de armazenar um valor de tipo incorreto em uma coluna. No entanto, em muitas condições os valores são convertidos para corresponder ao tipo de dados declarado da coluna. Consulte “Trabalhar com tipos de dados de banco de dados” na página 189 para obter mais informações. O tempo de execução não impõe restrições quanto a valores de chave externa. Em outras palavras, os valores de chave externa não precisam corresponder ao valor de uma chave primária existente. Além dos tipos de restrição predefinidos, o mecanismo SQL de tempo de execução permite o uso de disparadores. O disparador é como um manipulador de eventos. Ele consiste em um conjunto de instruções predefinidas que são executadas quando acontece uma determinada ação. Por exemplo, é possível definir um disparador que seja executado quando dados forem inseridos ou excluídos de uma tabela específica. Um uso possível de um disparador é examinar alterações feitas em dados e fazer com que ocorra um erro se as condições especificadas não forem atendidas. Conseqüentemente, um disparador pode atender ao mesmo objetivo de uma restrição, e as estratégias para evitar e se recuperar de erros de restrição também se aplicam a erros gerados por disparadores. Porém, a id de erro dos erros gerados por disparadores é diferente da id de erro dos erros de restrição. O conjunto de restrições que se aplicam a uma tabela em particular é determinado enquanto você está criando um aplicativo. Elaborar restrições com consciência facilita que você crie o aplicativo para evitar e se recuperar de erros de constrição. No entanto, os erros de restrição são difíceis de prever e impedir sistematicamente. A previsão é difícil porque os erros de restrição só aparecem depois que são adicionados os dados do aplicativo. Os erros de restrição acontecem com dados que são adicionados a um banco de dados após sua criação. Com freqüência, esses erros são resultado do relacionamento entre os novos dados e os dados já existentes no banco de dados. As seguintes estratégias podem ajudá-lo a evitar muitos erros de restrição: Planeje cautelosamente a estrutura e as restrições do banco de dados A finalidade das restrições é impor regras de aplicativo e ajudar a proteger a integridade dos dados do banco de dados. Quando estiver planejando seu aplicativo, pense em como estruturar o banco de dados para dar suporte ao aplicativo. Como parte desse processo, identifique regras para seus dados; por exemplo, se certos valores não necessários, se um valor tem um padrão, se são permitidos valores duplicados e assim por diante. Essas regras orientam a definição de restrições do banco de dados. Especifique nomes de coluna explicitamente É possível criar uma instrução INSERT sem especificar explicitamente as colunas em que os valores deverão ser inseridos, mas fazê-lo é um risco desnecessário. Quando você nomeia explicitamente as colunas em que os valores deverão ser inseridos, pode permitir valores gerados de forma automática, colunas com valores padrão e colunas que permitam valores NULL. Além disso, quando você faz isso pode assegurar que todas as colunas NOT NULL terão um valor explícito inserido. Use valores padrão Sempre que você especificar uma restrição NOT NULL para uma coluna, se possível, especifique um valor padrão na definição de coluna. O código do aplicativo também pode fornecer valores padrão. Por exemplo, o código pode verificar se uma variável String é null e atribuir um valor a ela antes de usá-la para definir um valor de parâmetro de instrução. Valide os dados inseridos pelos usuários Verifique com antecedência os dados inseridos pelos usuários para ter certeza de que obedecem aos limites especificados pelas restrições, principalmente no caso de restrições NOT NULL e CHECK. Naturalmente, uma restrição UNIQUE é mais difícil de verificar porque, para fazer a verificação, é necessário executar uma consulta SELECT para determinar se os dados são exclusivos. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 189 Trabalhar com bancos de dados SQL locais Use disparadores Você pode criar um disparador que valide (e possivelmente substitua) os dados inseridos ou que tome outras medidas para corrigir dados inválidos. Esse procedimento de validação e correção pode evitar que aconteça um erro de restrição. Em vários aspectos, é mais difícil evitar os erros de restrição do que outros tipos de erro. Felizmente, existem diversas estratégias para se recuperar de erros de restrição sem tornar o aplicativo instável ou inutilizável: Use algoritmos de conflito Quando você define uma restrição em uma coluna, e quando cria uma instrução INSERT ou UPDATE, tem a opção de especificar um algoritmo de conflito. Um algoritmo de conflito define a ação que o banco de dados executa quando ocorre uma violação de restrição. Há várias ações possíveis que o mecanismo de banco de dados pode executar. O mecanismo de banco de dados pode encerrar uma única instrução ou uma transação inteira. Ele pode ignorar o erro. Ele pode até mesmo remover dados antigos e substituí-los pelos dados que o código está tentando armazenar. Para obter mais informações, consulte a seção “ON CONFLICT (algoritmos de conflito)” no apêndice “Suporte a SQL em bancos de dados locais” da Referência dos componentes e da linguagem do ActionScript 3.0. Disponibilize feedback de correção É possível identificar antecipadamente o conjunto de restrições que pode afetar um determinado comando SQL. Como conseqüência, você consegue prever os erros de restrição que podem ser causados por uma instrução. Dispondo dessa informação, você pode desenvolver a lógica do aplicativo para responder a um erro de restrição. Por exemplo, suponha que um aplicativo inclui um formulário de entrada de dados que permite inserir novos produtos. Se a coluna de nome de produto no banco de dados estiver definida com uma restrição UNIQUE, a ação de inserir uma linha de novo produto no banco de dados poderá causar um erro de restrição. Conseqüentemente, o aplicativo deve prever um erro de restrição. Quando o erro acontece, o aplicativo alerta o usuário indicando que o nome de produto especificado já está sendo utilizado e pede a ele para escolher outro nome. Outra resposta possível é permitir que o usuário visualize informações sobre o outro produto que tem o mesmo nome. Trabalhar com tipos de dados de banco de dados Quando uma tabela é criada em um banco de dados, a instrução SQL usada para criar a tabela define a afinidade, ou o tipo de dados, de cada coluna da tabela. Embora seja possível omitir declarações de afinidade, é uma boa idéia declarar explicitamente a afinidade de coluna nas instruções SQL CREATE TABLE. Como regra geral, qualquer objeto que você armazena em um banco de dados usando uma instrução INSERT é retornado como ocorrência do mesmo tipo de dados quando é executada uma instrução SELECT. No entanto, o tipo de dados do valor recuperado pode ser diferente, dependendo da afinidade da coluna do banco de dados na qual o valor está armazenado. Quando um valor é armazenado em uma coluna, se o respectivo tipo de dados não corresponde à afinidade de coluna, o banco de dados tenta converter o valor para que corresponda à afinidade de coluna. Por exemplo, se uma coluna de banco de dados está declarada com afinidade NUMERIC, o banco de dados tenta converter os dados inseridos em uma classe de armazenamento numérica (INTEGER ou REAL) antes de armazenar os dados. O banco de dados gera um erro se não é possível converter os dados. De acordo com esta regra, se a String “12345” é inserida em uma coluna NUMERIC, o banco de dados automaticamente a converte no valor inteiro 12345 antes de armazená-la no banco de dados. Quando recuperado com uma instrução SELECT, o valor é retornado como uma ocorrência de um tipo de dados numérico (por exemplo, Number) e não como uma ocorrência de String. A melhor maneira de evitar a conversão indesejada de tipos de dados é seguir duas regras. Primeiro, defina cada coluna com a afinidade que corresponda ao tipo de dados que pretende armazenar. Em seguida, insira apenas valores cujo tipo de dados corresponda à afinidade definida. Se você seguir essas regras, terá dois benefícios. Quando você inserir os dados, eles não serão convertidos inesperadamente (com a possibilidade de perderem o significado pretendido). Além disso, quando você recupera os dados, eles são retornados com o tipo de dados original. Para obter mais informações sobre os tipos de afinidade de coluna disponíveis e como usar tipos de dados em instruções SQL, consulte a seção “Suporte ao tipo de dados” no apêndice “Suporte a SQL em bancos de dados locais” da Referência dos componentes e da linguagem do ActionScript 3.0. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 190 Trabalhar com bancos de dados SQL locais Uso de operações de banco de dados síncronas e assíncronas As seções anteriores descreveram operações comuns de banco de dados, como recuperar, inserir, atualizar e excluir dados, além da criação de um arquivo de banco de dados e de tabelas e outros objetos de um banco de dados. Os exemplos demonstraram como executar essas operações de maneira assíncrona e síncrona. Como lembrete, no modo de execução assíncrona, você instrui o mecanismo de banco de dados a executar uma operação. O mecanismo de banco de dados então trabalha em segundo plano enquanto o aplicativo continua a executar. Quando a operação é concluída, o mecanismo de banco de dados despacha um evento para alertar você sobre o fato. O principal benefício da execução assíncrona é que o tempo de execução realiza as operações de banco de dados em segundo plano, enquanto o código do aplicativo principal continua a executar. Isso é importante principalmente quando a operação é bastante demorada. Por outro lado, no modo de execução síncrona, as operações não são executadas em segundo plano. Você instrui o mecanismo de banco de dados a executar uma operação. O código pausa nesse ponto enquanto o mecanismo de banco de dados faz o seu trabalho. Quando a operação é concluída, a execução prossegue com a próxima linha do código que você criou. Uma única conexão de banco de dados não pode executar algumas operações ou instruções em modo síncrono e outras em modo assíncrono. Você especifica se SQLConnection opera de forma síncrona ou assíncrona quando abre a conexão com o banco de dados. Se você chamar SQLConnection.open(), a conexão funcionará no modo de execução síncrona; se você chamar SQLConnection.openAsync(), ela funcionará no modo de execução assíncrona. Uma vez que uma ocorrência de SQLConnection é conectada a um banco de dados usando open() ou openAsync(), ela é fixada à execução síncrona ou assíncrona. Uso de operações de banco de dados síncronas Há pouca diferente no código que você usa para executar e responder a operações na execução síncrona em comparação com o código para o modo de execução assíncrona. As principais diferenças entre as duas abordagens estão em duas áreas. A primeira é executar uma operação que depende de outra operação (como linhas de resultado SELECT ou a chave primária da linha adicionada por uma instrução INSERT). A segunda área de diferença é o tratamento de erros. Criação de código para operações síncronas A principal diferença entre a execução síncrona e assíncrona é que, no modo síncrono, você cria o código como uma única série de etapas. Por outro lado, no código assíncrono, você registra ouvintes de evento e com freqüência divide as operações entre métodos de ouvinte. Quando um banco de dados é conectado no modo de execução síncrona, você pode executar uma série de operações de banco de dados em seqüência em um único bloco de código. O exemplo abaixo demonstra esta técnica: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 191 Trabalhar com bancos de dados SQL locais var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); // open the database conn.open(dbFile, OpenMode.UPDATE); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit(); Como você pode ver, é possível chamar os mesmos métodos para executar operações de banco de dados independentemente de usar a execução síncrona ou assíncrona. As principais diferenças entre as duas abordagens são executar uma operação que depende de outra operação e como tratar de erros. Execução de uma operação que depende de outra Quando você usa o modo de execução síncrona, não precisa criar um código que monitore um evento para determinar quando uma operação é concluída. Em vez disso, você pode presumir que, se uma operação em uma linha de código foi concluída com sucesso, a execução continuará na próxima linha de código. Conseqüentemente, para executar uma operação que depende do sucesso de outra, basta criar o código dependente logo depois da operação da qual ela depende. Por exemplo, para codificar um aplicativo para iniciar uma transação, executar uma instrução INSERT, recuperar a chave primária da linha inserida, inserir essa chave primária em outra linha de uma outra tabela e, por fim, confirmar a transação, o código pode ser todo criado como uma série de instruções. O seguinte exemplo demonstra essas operações: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 192 Trabalhar com bancos de dados SQL locais var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); // open the database conn.open(dbFile, SQLMode.UPDATE); // start a transaction conn.begin(); // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName) " + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number) " + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // commit the transaction conn.commit(); Tratamento de erros na execução síncrona No modo de execução síncrona, você não monitora um evento de erro para determinar se uma operação falhou. Em vez disso, coloque qualquer código que possa disparar erros em um conjunto de blocos de código try..catch..finally. Coloque o código gerador de erro no bloco try. Grave as ações a serem executadas em resposta a cada tipo de erro em blocos catch separados. Coloque qualquer código que você queira sempre executar independentemente de sucesso ou falha (por exemplo, encerrar uma conexão de banco de dados não mais necessária) em um bloco finally. O exemplo a seguir demonstra o uso de blocos try..catch..finally para tratamento de erros. Ele aproveita o exemplo anterior adicionando código de tratamento de erro: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 193 Trabalhar com bancos de dados SQL locais var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); // open the database conn.open(dbFile, SQLMode.UPDATE); // start a transaction conn.begin(); try { // add the customer record to the database var insertCustomer:SQLStatement = new SQLStatement(); insertCustomer.sqlConnection = conn; insertCustomer.text = "INSERT INTO customers (firstName, lastName)" + "VALUES ('Bob', 'Jones')"; insertCustomer.execute(); var customerId:Number = insertCustomer.getResult().lastInsertRowID; // add a related phone number record for the customer var insertPhoneNumber:SQLStatement = new SQLStatement(); insertPhoneNumber.sqlConnection = conn; insertPhoneNumber.text = "INSERT INTO customerPhoneNumbers (customerId, number)" + "VALUES (:customerId, '800-555-1234')"; insertPhoneNumber.parameters[":customerId"] = customerId; insertPhoneNumber.execute(); // if we've gotten to this point without errors, commit the transaction conn.commit(); } catch (error:SQLError) { // rollback the transaction conn.rollback(); } Noções básicas sobre o modelo de execução assíncrona Uma preocupação comum sobre o uso do modo de execução assíncrona é a suposição de que não é possível começar a executar uma ocorrência de SQLStatement se outra ocorrência de SQLStatement está em execução na mesma conexão de banco de dados. Na verdade, essa suposição não está correta. Durante a execução de uma ocorrência de SQLStatement, não é possível alterar a propriedade text da instrução. Contudo, se você usar uma ocorrência de SQLStatement à parte para cada instrução SQL que deseja executar, poderá chamar o método execute() de um SQLStatement enquanto outra ocorrência de SQLStatement ainda estiver sendo executada, sem causar erro. Internamente, quando você executa operações de banco de dados utilizando o modo de execução assíncrona, cada conexão de banco de dados (cada ocorrência de SQLConnection) tem sua própria fila ou lista de operações que está instruída a executar. O tempo de execução realiza cada operação em seqüência, na ordem em que são adicionadas à fila. Quando você cria uma ocorrência de SQLStatement e chama o método execute() relacionado, a operação de execução dessa instrução é adicionada à fila da conexão. Se nenhuma operação estiver sendo executada nessa ocorrência de SQLConnection, a instrução começará a ser executada em segundo plano. Suponha que, dentro do DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 194 Trabalhar com bancos de dados SQL locais mesmo bloco de código, você crie outra ocorrência de SQLStatement e também chame o método execute() daquele método. A operação que executa essa segunda instrução é adicionada à fila depois da primeira instrução. Assim que é concluída a execução da primeira instrução, o tempo de execução passa para a próxima operação da fila. O processamento das operações subseqüentes na fila acontece em segundo plano, mesmo quando o evento result da primeira operação está sendo despachado no código do aplicativo principal. O código abaixo demonstra esta técnica: // Using asynchronous execution mode var stmt1:SQLStatement = new SQLStatement(); stmt1.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt1.execute(); // At this point stmt1's execute() operation is added to conn's execution queue. var stmt2:SQLStatement = new SQLStatement(); stmt2.sqlConnection = conn; // ... Set statement text and parameters, and register event listeners ... stmt2.execute(); // At this point stmt2's execute() operation is added to conn's execution queue. // When stmt1 finishes executing, stmt2 will immediately begin executing // in the background. Ocorre um importante efeito colateral pelo fato de o banco de dados executar as próximas instruções em fila de maneira automática. Se uma instrução depende do resultado de outra operação, não é possível adicioná-la à fila (em outras palavras, você não pode chamar o método execute() relacionado) até a primeira operação ser concluída. Isso acontece porque, depois que você chamou o método execute() da segunda instrução, não é possível alterar as propriedades text ou parameters dela. Nesse caso, você deve aguardar o evento indicando que a primeira operação foi concluída antes de iniciar a próxima operação. Por exemplo, se você quiser executar uma instrução no contexto de uma transação, a execução da instrução dependerá da operação de abrir a transação. Após chamar o método SQLConnection.begin() para abrir a transação, você terá de aguardar que a ocorrência de SQLConnection despache seu evento begin. Só então você poderá chamar o método execute() da ocorrência de SQLStatement. Neste exemplo, o modo mais simples de organizar o aplicativo para assegurar que as operações sejam executadas corretamente é criar um método que seja registrado como ouvinte do evento begin. O código para chamar o método SQLStatement.execute() é colocado dentro do método desse ouvinte. Uso da criptografia com bancos de dados SQL Todos os aplicativos do Adobe AIR compartilham o mesmo mecanismo do banco de dados local. Conseqüentemente, qualquer aplicativo do AIR pode se conectar, ler e gravar em qualquer arquivo do banco de dados não criptografado. Começando com o Adobe AIR 1.5, o AIR inclui a capacidade de criar e se conectar a arquivos do banco de dados criptografado. Quando você usa um banco de dados criptografado, para se conectar a ele um aplicativo deve fornecer a chave de criptografia correta. Se a chave de criptografia incorreta (ou nenhuma chave) for fornecida, o aplicativo não poderá se conectar ao banco de dados. Conseqüentemente, o aplicativo não poderá ler, gravar ou alterar dados do banco de dados. Para usar um banco de dados criptografado, você deve criar o banco de dados como banco de dados criptografado. Com um banco de dados criptografado existente, é possível abrir uma conexão com o banco de dados. Você também pode alterar a chave de criptografia de um banco de dados criptografado. Em vez de criar e estabelecer conexão com bancos de dados criptografados, as técnicas para trabalhar com um banco de dados criptografado são as mesmas que para um banco de dados não criptografado. Especificamente, a execução de instruções SQL ocorre da mesma forma em bancos de dados criptografados e não criptografados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 195 Trabalhar com bancos de dados SQL locais Uso de um banco de dados criptografado A criptografia é útil sempre que você desejar restringir o acesso às informações armazenadas em um banco de dados. A funcionalidade de criptografia do banco de dados do Adobe AIR pode ser usada para várias finalidades. Estes são exemplos de casos em que você pode usar um banco de dados criptografado: • Um cache somente leitura de dados de aplicativos privados baixados de um servidor • Um armazenamento de aplicativo local para dados privados sincronizado com um servidor (os dados são enviados e carregados do servidor) • Arquivos criptografados usados como formato de arquivo para documentos criados e editados pelo aplicativo. Os arquivos podem ser privados para um usuário ou projetados para compartilhamento entre todos os usuários do aplicativo. • Qualquer outro uso de um armazenamento local de dados, como os descrito em “Usos de bancos de dados SQL locais” na página 165, onde os dados devem ser mantidos privados de pessoas com acesso ao computador ou aos arquivos do banco de dados. Compreender o motivo pelo qual você deseja usar um banco de dados criptografado ajuda a decidir como arquitetar seu aplicativo. Especificamente, ele pode afetar a forma que seu aplicativo cria, obtém ou armazena a chave de criptografia para o banco de dados. Para obter mais informações sobre essas considerações, consulte “Considerações para usar criptografia com um banco de dados” na página 199. Diferente de um banco de dados criptografado, um mecanismo alternativo para manter dados confidenciais privados é o armazenamento local criptografado. Com o armazenamento local criptografado, você armazena um único valor ByteArray usando uma chave String. Apenas o aplicativo do AIR que armazenou o valor pode acessá-lo, e somente no computador em que ele está armazenado. Com o armazenamento local criptografado, não é necessário criar sua própria chave de criptografia. Por esses motivos, o armazenamento local criptografado é mais adequado para armazenar facilmente um único valor ou um conjunto de valores que possa ser facilmente codificado em um ByteArray. Um banco de dados criptografado é mais adequado para conjuntos de dados maiores, onde o armazenamento de dados e consultas estruturadas são desejáveis. Para obter mais informações sobre o uso de armazenamento local criptografado, consulte “Armazenamento de dados criptografados” na página 215. Criação de um banco de dados criptografado Para usar um banco de dados criptografado, o arquivo do banco de dados deve ser criptografado quando ele for criado. Quando um banco de dados é criado como não criptografado, ele pode não ser criptografado posteriormente. Da mesma forma, um banco de dados criptografado não pode passar a não criptografado posteriormente. Se necessário, você também pode alterar a chave de criptografia de um banco de dados criptografado. Para obter detalhes, consulte “Alteração da chave de criptografia de um banco de dados” na página 198. Se você tiver um banco de dados existente que não seja criptografado e desejar usar a criptografia de banco de dados, poderá criar um novo banco de dados criptografado e copiar a estrutura de tabela e os dados existentes no novo banco de dados. Criar um banco de dados criptografado é quase idêntico a criar um banco de dados não criptografado, como descrito em “Criação de um banco de dados” na página 169. Primeiro você cria uma instância do SQLConnection que representa a conexão ao banco de dados. Crie o banco de dados chamando o método open() ou o método openAsync() do objeto do SQLConnection, especificando para a localização do banco de dados um arquivo que ainda não exista. A única diferença na criação de um banco de dados criptografado é que você fornece um valor para o parâmetro encryptionKey (o quinto parâmetro do método open() e o sexto parâmetro do método openAsync()). Um valor do parâmetro encryptionKey válido é um objeto ByteArray contendo exatamente 16 bytes. O exemplo a seguir demonstra a criação de um banco de dados criptografado que é aberto no modo de execução assíncrona. Para simplicidade, neste exemplo a chave de criptografia é codificada no código do aplicativo. No entanto, essa técnica é altamente desencorajada, pois não é segura. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 196 Trabalhar com bancos de dados SQL locais import import import import import flash.data.SQLConnection; flash.data.SQLMode; flash.events.SQLErrorEvent; flash.events.SQLEvent; flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey:ByteArray = new ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! conn.openAsync(dbFile, SQLMode.CREATE, null, false, 1024, encryptionKey); function openHandler(event:SQLEvent):void { trace("the database was created successfully"); } function errorHandler(event:SQLErrorEvent):void { trace("Error message:", event.error.message); trace("Details:", event.error.details); } O exemplo a seguir demonstra a criação de um banco de dados criptografado que é aberto no modo de execução síncrona. Para simplicidade, neste exemplo a chave de criptografia é codificada no código do aplicativo. No entanto, essa técnica é altamente desencorajada, pois não é segura. import flash.data.SQLConnection; import flash.data.SQLMode; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey:ByteArray = new ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! try { conn.open(dbFile, SQLMode.CREATE, false, 1024, encryptionKey); trace("the database was created successfully"); } catch (error:SQLError) { trace("Error message:", error.message); trace("Details:", error.details); } Para obter um exemplo que demonstre uma forma recomendada de gerar uma chave de criptografia, consulte “Exemplo: Geração e uso de uma chave de criptografia” na página 200. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 197 Trabalhar com bancos de dados SQL locais Conexão com um banco de dados criptografado Da mesma forma que criar um banco de dados criptografado, o procedimento para abrir uma conexão com um banco de dados criptografado é como conectar-se a um banco de dados não criptografado. Esse procedimento é descrito com mais detalhes em “Conexão com um banco de dados” na página 172. Use o método open() para abrir uma conexão no modo de execução síncrona ou o método openAsync() para abri-la no modo de execução assíncrona. A única diferença é que para abrir um banco de dados criptografado, especifica o valor correto para o parâmetro encryptionKey (o quinto parâmetro do método open() e o sexto parâmetro do método openAsync()). Se a chave de criptografia fornecida não for a correta, ocorre um erro. Para o método open(), é lançada uma exceção SQLError. Para o método openAsync(), o objeto SQLConnection despacha um SQLErrorEvent, cuja propriedade error contém um objeto SQLError. Em qualquer um dos casos, o objeto SQLError gerado pela exceção tem o valor de propriedade errorID 3138. Essa ID de erro corresponde à mensagem de erro "Arquivo aberto não é arquivo do banco de dados". O exemplo a seguir demonstra a abertura de um banco de dados criptografado em modo de execução assíncrona. Para simplicidade, neste exemplo a chave de criptografia é codificada no código do aplicativo. No entanto, essa técnica é altamente desencorajada, pois não é segura. import import import import import flash.data.SQLConnection; flash.data.SQLMode; flash.events.SQLErrorEvent; flash.events.SQLEvent; flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, errorHandler); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey:ByteArray = new ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! conn.openAsync(dbFile, SQLMode.UPDATE, null, false, 1024, encryptionKey); function openHandler(event:SQLEvent):void { trace("the database opened successfully"); } function errorHandler(event:SQLErrorEvent):void { if (event.error.errorID == 3138) { trace("Incorrect encryption key"); } else { trace("Error message:", event.error.message); trace("Details:", event.error.details); } } O exemplo a seguir demonstra a abertura de um banco de dados criptografado em modo de execução síncrona. Para simplicidade, neste exemplo a chave de criptografia é codificada no código do aplicativo. No entanto, essa técnica é altamente desencorajada, pois não é segura. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 198 Trabalhar com bancos de dados SQL locais import flash.data.SQLConnection; import flash.data.SQLMode; import flash.filesystem.File; var conn:SQLConnection = new SQLConnection(); var dbFile:File = File.applicationStorageDirectory.resolvePath("DBSample.db"); var encryptionKey:ByteArray = new ByteArray(); encryptionKey.writeUTFBytes("Some16ByteString"); // This technique is not secure! try { conn.open(dbFile, SQLMode.UPDATE, false, 1024, encryptionKey); trace("the database was created successfully"); } catch (error:SQLError) { if (error.errorID == 3138) { trace("Incorrect encryption key"); } else { trace("Error message:", error.message); trace("Details:", error.details); } } Para obter um exemplo que demonstre uma forma recomendada de gerar uma chave de criptografia, consulte “Exemplo: Geração e uso de uma chave de criptografia” na página 200. Alteração da chave de criptografia de um banco de dados Quando um banco de dados é criptografado, você pode alterar a chave de criptografia para o banco de dados posteriormente. Para isso, primeiro abra uma conexão com o banco de dados criando uma instância de SQLConnection e chamando seu método open() ou openAsync(). Quando o banco de dados for conectado, chame o método reencrypt(), enviando a nova chave de criptografia como um argumento. Como a maioria das operações de banco de dados, o comportamento do método reencrypt() depende se a conexão do banco de dados usa modo de execução síncrona ou assíncrona. Se você usar o método open() para conectar-se ao banco de dados, a operação de reencrypt() será executada de forma síncrona. Quando a operação é concluída, a execução prossegue com a próxima linha do código. var newKey:ByteArray = new ByteArray(); // ... generate the new key and store it in newKey conn.reencrypt(newKey); Por outro lado, se a conexão do banco de dados for aberta com o método openAsync(), a operação de reencrypt() será assíncrona. Chamar reencrypt() inicia o processo de recriptografia. Quando a operação é concluída, o objeto SQLConnection despacha um evento reencrypt. Use um ouvinte de evento para determinar quando a recriptografia será concluída: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 199 Trabalhar com bancos de dados SQL locais var newKey:ByteArray = new ByteArray(); // ... generate the new key and store it in newKey conn.addEventListener(SQLEvent.REENCRYPT, reencryptHandler); conn.reencrypt(newKey); function reencryptHandler(event:SQLEvent):void { // save the fact that the key changed } A operação reencrypt() será executada na sua própria transação. Se a operação for interrompida ou falhar (por exemplo, se o aplicativo for fechado antes da conclusão da operação), a transação será revertida. Nesse caso, a chave de criptografia ainda será a chave de criptografia do banco de dados. O método reencrypt() não pode ser usado para remover a criptografia de um banco de dados. Enviar um valor null ou chave de criptografia que não seja um ByteArray de 16 bytes para o método reencrypt() resulta em erro. Considerações para usar criptografia com um banco de dados A seção “Uso de um banco de dados criptografado” na página 195 apresenta vários casos em que você pode usar um banco de dados criptografado. É óbvio que as situações de uso dos aplicativos diferentes (incluindo essas e outras situações) têm requisitos de privacidade diferentes. A forma que você arquiteta o uso de criptografia no seu aplicativo tem importante papel no controle do grau de privacidade dos dados de um banco de dados. Por exemplo, se você estiver usando um banco de dados criptografado para manter os dados pessoais privados, mesmo de usuários do mesmo computador, o banco de dados de cada usuário deverá ter a própria chave de criptografia. Para obter segurança máxima, seu aplicativo pode gerar a chave de uma senha digitada por um usuário. Basear a chave de criptografia em uma senha garante que os dados se mantenham preservados, mesmo se qualquer outra pessoa entrar na conta do usuário no computador. Por outro lado, suponha que você deseje que um arquivo do banco de dados seja legível para qualquer usuário do seu aplicativo, mas não para os demais aplicativos. Nesse caso, todas as cópias do aplicativo instaladas precisam de acesso a uma chave de criptografia compartilhada. Você pode projetar seu aplicativo e, em particular, a técnica usada para gerar a chave de criptografia, de acordo com o nível de privacidade que você deseja para os dados do aplicativo. A lista a seguir fornece sugestões de design para vários níveis de privacidade de dados. • Para tornar um banco de dados acessível a qualquer usuário que tenha acesso ao aplicativo em qualquer computador, use uma única chave disponível em todas as instâncias do aplicativo. Por exemplo, na primeira vez que um aplicativo for executado, ele poderá baixar a chave de criptografia compartilhada de um servidor usando um protocolo seguro, como SSL. Em seguida, ele poderá salvar a chave no armazenamento local criptografado para uso futuro. Como alternativa, criptografe os dados por usuário no computador e sincronize os dados com um armazenamento de dados remoto, como servidor, para tornar os dados portáteis. • Para tornar um banco de dados acessível para um único usuário em qualquer computador, gere a chave de criptografia a partir de um segredo do usuário (como uma senha). Especificamente, não use nenhum valor associado a um computador específico (como um valor armazenado no armazenamento local criptografado) para gerar a chave. Como alternativa, criptografe os dados por usuário no computador e sincronize os dados com um armazenamento de dados remoto, como servidor, para tornar os dados portáteis. • Para tornar um banco de dados acessível somente para um único indivíduo em um único computador, gere a chave de uma senha e um salt gerado. Para obter um exemplo dessa técnica, consulte “Exemplo: Geração e uso de uma chave de criptografia” na página 200. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 200 Trabalhar com bancos de dados SQL locais A seguir há algumas considerações adicionais sobre segurança que são importantes lembrar ao projetar um aplicativo para usar um banco de dados criptografado. • Um sistema só é seguro como seu link mais fraco. Se você estiver usando uma senha gerada pelo usuário para gerar uma chave de criptografia, considere impor o restrições de complexidade e tamanho mínimo às senhas. Uma senha curta que use somente caracteres básicos pode ser adivinhada rapidamente. • O código-fonte de um aplicativo do AIR é armazenado no computador de um usuário em texto simples (para conteúdo HTML) ou em um formato binário facilmente descompilável (para conteúdo SWF). Como o códigofonte é acessível, dois pontos a lembrar são: • Nunca codifique uma chave de criptografia no seu código-fonte • Sempre suponha que a técnica usada para gerar uma chave de criptografia (como gerador aleatório de caracteres ou um algoritmo de hash específico) possa ser facilmente descoberta por um invasor • A criptografia do banco de dados AIR usa o modo AES (padrão de criptografia avançado) com CCM (contador com CBC-MAC). Essa cifra de criptografia requer a combinação de uma chave inserida pelo usuário com um valor salt para ser segura. Para obter um exemplo, consulte “Exemplo: Geração e uso de uma chave de criptografia” na página 200. • Quando você opta por criptografar um banco de dados, todos os arquivos de discos usados pelo mecanismo de banco de dados juntamente com esse banco de dados são criptografados. No entanto, o mecanismo do banco de dados retém alguns dados temporariamente em um cache na memória para aprimorar o desempenho de tempos de leitura e gravação em transações. Todos os dados residentes na memória são criptografados. Se um invasor puder acessar a memória usada por um aplicativo do AIR, por exemplo usando um depurador, os dados do banco de dados aberto atualmente e não criptografado ficarão disponíveis. Exemplo: Geração e uso de uma chave de criptografia Esse aplicativo de exemplo demonstra uma técnica para gerar uma chave de criptografia. Esse aplicativo foi projetado para fornecer o nível mais alto de privacidade e segurança para dados do usuário. Um aspecto importante da segurança de dados privados é exigir que o usuário digite uma senha sempre que o aplicativo se conectar ao banco de dados. Conseqüentemente, conforme mostrado no exemplo, um aplicativo que requer este nível de privacidade nunca deverá armazenar diretamente a chave de criptografia do banco de dados. O aplicativo consiste em duas partes: uma classe ActionScript que gera uma chave de criptografia (a classe EncryptionKeyGenerator) e uma interface do usuário básica que demonstra como usar a classe. Para obter o códigofonte completo, consulte “Exemplo completo de código para gerar e usar chave de criptografia” na página 208. Usar a classe EncryptionKeyGenerator para obter uma cjave de criptografia segura A seção “Noções básicas da classe EncryptionKeyGenerator” na página 202 detalha as técnicas que a classe EncryptionKeyGenerator usa para gerar uma chave de criptografia de um banco de dados. No entanto, não é necessário entender esses detalhes para usar a classe EncryptionKeyGenerator no seu aplicativo. Siga essas etapas para usar a classe EncryptionKeyGenerator no seu aplicativo: 1 A classe EncryptionKeyGenerator está incluída no projeto biblioteca principal (as3corelib) do ActionScript 3.0 de código-fonte aberto. Você pode baixar o pacote as3corelib incluindo o código-fonte e a documentação. Você também pode baixar os arquivos SWC ou de código-fonte na página do projeto. 2 Coloque o código-fonte da classe EncryptionKeyGenerator (ou o SWC as3corelib) em um local onde o código- fonte do seu aplicativo possa encontrá-lo. 3 No código-fonte do aplicativo, adicione uma instrução import para a classe EncryptionKeyGenerator. import com.adobe.air.crypto.EncryptionKeyGenerator; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 201 Trabalhar com bancos de dados SQL locais 4 Antes do ponto onde o código cria o banco de dados ou abre uma conexão para ele, adicione o código para criar uma ocorrência EncryptionKeyGenerator chamando o construtor EncryptionKeyGenerator(). var keyGenerator:EncryptionKeyGenerator = new EncryptionKeyGenerator(); 5 Obtenha uma senha do usuário: var password:String = passwordInput.text; if (!keyGenerator.validateStrongPassword(password)) { // display an error message return; } A ocorrência EncryptionKeyGenerator usa essa senha como base da chave de criptografia (mostrado na próxima etapa). A ocorrência EncryptionKeyGenerator testa a senha em relação a alguns requisitos de validação de senha forte. Em caso de falha na validação, ocorre um erro. Como o código de exemplo mostra, você pode verificar a senha antecipadamente chamando o método validateStrongPassword() do objeto EncryptionKeyGenerator. Dessa forma, você pode determinar se a senha atende aos requisitos mínimos de uma senha forte e evita que haja erro. 6 Gere a chave de criptografia da senha: var encryptionKey:ByteArray = keyGenerator.getEncryptionKey(password); O método getEncryptionKey() gera e retorna a chave de criptografia (um ByteArray de 16 bytes). Em seguida, você pode usar a chave de criptografia para criar seu novo banco de dados criptografado ou abrir um já existente. O método getEncryptionKey() tem um parâmetro obrigatório, que é a senha obtida na etapa 5. Nota: Para manter o maior nível de segurança e privacidade dos dados, o aplicativo deve requerer que o usuário digite uma senha sempre que se conectar ao banco de dados. Não armazene diretamente a senha do usuário ou a chave de criptografia do banco de dados. Isso expõe a riscos de segurança. Em vez disso, conforme demonstrado nesse exemplo, o aplicativo deve usar a mesma técnica para derivar a chade de criptografia da senha, ao criar o banco de dados criptografado e quando se conectar a ele mais tarde. O método getEncryptionKey() também aceita um segundo parâmetro (opcional), o parâmetro overrideSaltELSKey. O EncryptionKeyGenerator cria um valor aleatório (conhecido como salt) que é usado como parte da chave de criptografia. Para ser capaz de criar novamente a chave de criptografia, o valor salt é armazenado no armazenamento local criptografado (ELS) do seu aplicativo do AIR. Por padrão, a classe EncryptionKeyGenerator usa uma String específica como chave ELS. Embora improvável, é possível que a chave possa entrar em conflito com outra chave que o aplicativo usa. Em vez de usar a chave padrão, talvez você deseje especificar sua própria chave ELS. Nesse caso, especifique uma chave personalizada, passando-a como segundo parâmetro getEncryptionKey(), conforme mostrado aqui: var customKey:String = "My custom ELS salt key"; var encryptionKey:ByteArray = keyGenerator.getEncryptionKey(password, customKey); 7 Criar ou abrir o banco de dados Com a chave de criptografia retornada pelo método getEncryptionKey(), o código pode criar um novo banco de dados criptografado ou tentar abrir o banco de dados criptografado existente. Em ambos os casos, você usa o método open() ou openAsync() da classe SQLConnection, conforme descrito em “Criação de um banco de dados criptografado” na página 195 e “Conexão com um banco de dados criptografado” na página 197. Nesse exemplo, o aplicativo foi projetado para abrir o banco de dados em modo de execução assíncrona. O código configura os ouvintes do evento apropriados e chama o método openAsync(), enviando a chave de criptografia como argumento final. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 202 Trabalhar com bancos de dados SQL locais conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, openError); conn.openAsync(dbFile, SQLMode.CREATE, null, false, 1024, encryptionKey); Nos métodos do ouvinte, o código remove os registros do ouvinte do evento. Em seguida, ele exibe uma mensagem de status indicando se o banco de dados foi criado, aberto ou se ocorreu um erro. A parte mais notável desses manipuladores de eventos está no método openError(). Nesse método, a instrução if verifica se o banco de dados existe (o que significa que o código está tentando se conectar a um banco de dados existente) e se a ID do erro corresponde à constante EncryptionKeyGenerator.ENCRYPTED_DB_PASSWORD_ERROR_ID. Se ambas as condições forem verdadeiras, isso significa provavelmente que a senha inserida pelo usuário está incorreta. (Isso também pode significar que o arquivo especificado não é de maneira nenhuma um arquivo de banco de dados.) A seguir temos o código que verifica a ID do erro: if (!createNewDB && event.error.errorID == EncryptionKeyGenerator.ENCRYPTED_DB_PASSWORD_ERROR_ID) { statusMsg.text = "Incorrect password!"; } else { statusMsg.text = "Error creating or opening database."; } Para obter o código completo dos ouvintes de eventos de exemplo, consulte “Exemplo completo de código para gerar e usar chave de criptografia” na página 208. Noções básicas da classe EncryptionKeyGenerator Não é necessário compreender o funcionamento interno da classe EncryptionKeyGenerator para usá-la com o fim de criar uma chave de criptografia segura para o banco de dados do aplicativo. O processo para usar a classe está explicado em “Usar a classe EncryptionKeyGenerator para obter uma cjave de criptografia segura” na página 200. No entanto, pode ser conveniente entender as técnicas que a classe utiliza. Por exemplo, pode ser conveniente adaptar a classe ou incorporar algumas de suas técnicas em situações nas quais um nível diferente de privacidade de dados é desejado. A classe EncryptionKeyGenerator está incluída no projeto de biblioteca central (as3corelib) do ActionScript 3.0 de código-fonte aberto. Você pode fazer o download dopacote as3corelib, incluindo o código-fonte e a documentação. Também é possível exibir o código-fonte no site do projeto ou baixá-lo para acompanhar juntamente com as explicações. Quando o código cria uma ocorrência EncryptionKeyGenerator e chama o respectivo método getEncryptionKey(), várias etapas são realizadas para garantir que apenas o usuário com permissão possa acessar os dados. O processo é o mesmo para gerar uma chave de criptografia de uma senha inserida pelo usuário antes de o banco de dados ter sido criado, bem como criar novamente a chave de criptografia para abrir o banco de dados. Obter e validar uma senha forte Quando o código chama o método getEncryptionKey(), ele passa uma senha como um parâmetro. A senha é usada como base para a chave de criptografia. Usando informações que somente o usuário conheça, esse design garante que somente o usuário que saiba a senha possa acessar os dados do banco de dados. Mesmo se um invasor acessar a conta do usuário no computador, não poderá entrar no banco de dados sem saber a senha. Para fornecer máxima proteção, o aplicativo nunca armazena a senha. No aplicativo de exemplo, passwordInput é o nome da ocorrência de um componente TextInput em que o usuário digita a senha. Em vez de manipular o valor text do componente diretamente, o aplicativo copia a senha em uma variável chamada password. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 203 Trabalhar com bancos de dados SQL locais var password:String = passwordInput.text; Em seguida, o aplicativo de exemplo cria uma ocorrência EncryptionKeyGenerator e chama seu método getEncryptionKey(), usando a variável password como argumento: var keyGenerator:EncryptionKeyGenerator = new EncryptionKeyGenerator(); var encryptionKey:ByteArray = keyGenerator.getEncryptionKey(password); A primeira etapa que a classe EncryptionKeyGenerator executa quando o método getEncryptionKey() é chamado, é verificar a senha digitada pelo usuário para garantir que ela atende aos requisitos de senha forte. Nesse caso, a senha deve ter entre 8 e 32 caracteres. Ela deve conter letras maiúsculas e minúsculas e pelo menos um número ou caractere simbólico. A expressão regular que marca esse padrão é definida como uma constante chamada de STRONG_PASSWORD_PATTERN: private static const STRONG_PASSWORD_PATTERN:RegExp = /(?=^.{8,32}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/; O código que verifica a senha está no método validateStrongPassword() da classe EncryptionKeyGenerator. O código é o seguinte: public function vaidateStrongPassword(password:String):Boolean { if (password == null || password.length <= 0) { return false; } return STRONG_PASSWORD_PATTERN.test(password)) } O método getEncryptionKey() chama o método validateStrongPassword() e, se a senha não é válida, lança uma exceção. O método validateStrongPassword() é um método público para que o código possa verificar a senha sem chamar o método getEncryptionKey(), para evitar um erro. Expanda a senha para 256 bits Mais tarde no processo, a senha deverá ter 256 bits. Em vez de exigir que cada usuário insira uma senha com exatamente 256 bits (32 caracteres), o código cria uma senha maior, repetindo os caracteres da senha. O método getEncryptionKey() chama o método concatenatePassword() para executar a tarefa de criar a senha longa. var concatenatedPassword:String = concatenatePassword(password); A seguir, temos o código do método concatenatePassword(): DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 204 Trabalhar com bancos de dados SQL locais private function concatenatePassword(pwd:String):String { var len:int = pwd.length; var targetLength:int = 32; if (len == targetLength) { return pwd; } var repetitions:int = Math.floor(targetLength / len); var excess:int = targetLength % len; var result:String = ""; for (var i:uint = 0; i < repetitions; i++) { result += pwd; } result += pwd.substr(0, excess); return result; } Se a senha tem menos de 256 bits, o código concatena a senha com ele mesmo para torná-la 256 bits. Se o comprimento não funcionar exatamente, a última repetição será reduzida para obter exatamente 256 bits. Gerar ou recuperar um valor de salt de 256 bits A próxima etapa é obter um valor de salt de 256 bits que, posteriormente, será combinado com a senha. Um salt é um valor aleatório adicionado ou combinado com um valor inserido pelo usuário para formar uma senha. Usar um salt com uma senha garante que mesmo se um usuário escolher uma palavra real ou termo comum como senha, a combinação senha mais salt que o sistema usa será um valor aleatório. Isso, de maneira não aleatória, ajuda a proteger contra um ataque ao dicionário, em que um invasor usa uma lista de palavras para tentar adivinhar uma senha. Além disso, gerando o valor salt e armazenando-o no armazenamento local criptografado, ele é associado à conta do usuário no computador em que o arquivo do banco de dados está localizado. Se o aplicativo estiver chamando o método getEncryptionKey() pela primeira vez, o código criará um valor salt aleatório de 256 bits. Caso contrário, o código carregará o valor de salt do armazenamento local criptografado. O salt é armazenado em uma variável chamada de salt. O código determina se já foi criado um salt, ao tentar carregar o salt do armazenamento local criptografado: var salt:ByteArray = EncryptedLocalStore.getItem(saltKey); if (salt == null) { salt = makeSalt(); EncryptedLocalStore.setItem(saltKey, salt); } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 205 Trabalhar com bancos de dados SQL locais Se o código estiver criando um novo valor salt, o método makeSalt() gera um valor aleatório de 256 bits. Como o valor é eventualmente armazenado no armazenamento local criptografado, ele é gerado como um objeto ByteArray. O método makeSalt() usa o método Math.random() para gerar aleatoriamente o valor. O método Math.random() não pode gerar 256 bits de uma vez. Em vez disso, o código usa um loop para chamar o Math.random() oito vezes. A cada vez, um valor uint aleatório entre 0 e 4294967295 (o valor uint máximo) é gerado. Um valor uint é usado por conveniência, pois um uint usa exatamente 32 bits. Quando oito valores uint são gravados no ByteArray, é gerado um valor de 256 bits. Este é o código para o método makeSalt(): private function makeSalt():ByteArray { var result:ByteArray = new ByteArray; for (var i:uint = 0; i < 8; i++) { result.writeUnsignedInt(Math.round(Math.random() * uint.MAX_VALUE)); } return result; } Quando o código está salvando o salt no armazenamento local criptografado (ELS) ou recuperando o salt do ELS, ele precisa da chave String com a qual o salt é salvo. Sem saber a chave, o valor salt não pode ser recuperado. Nesse caso, a chave de criptografia não pode ser recriada todas as vezes para abrir novamente o banco de dados. Por padrão, o EncryptionKeyGenerator usa uma chave ELS predefinida que é definida na constante SALT_ELS_KEY. Em vez de usar a chave padrão, o código do aplicativo também pode especificar uma chave ELS para usar na chamada do método getEncryptionKey(). A Chave ELS padrão ou a chave ELS salt especificada pelo aplicativo é armazenada em uma variável chamada de saltKey. Essa variável é usada nas chamadas de EncryptedLocalStore.setItem() e EncryptedLocalStore.getItem(), como mostrado em uma listagem de código anterior. Combinar a senha de 256 bits e o salt usando o operador XOR O código agora tem uma senha de 256 bits e um valor salt de 256 bits. Em seguida, ele usa uma operação XOR em nível de bits para combinar o salt e a senha concatenada em um único valor. Efetivamente, essa técnica cria um senha de 256 bits que consiste em caracteres do intervalo inteiro de caracteres possíveis. Esse princípio é verdadeiro, embora muito provavelmente a entrada de senha real consista principalmente em caracteres alfanuméricos. Essa não-aleatoriedade elevada oferece o benefício de tornar o conjunto de senhas possíveis maior, sem exigir que o usuário digite uma senha longa e complexa. O resultado da operação XOR é armazenado na variável unhashedKey. O processo real de execução de um XOR em nível de bits nos dois valores ocorre no método xorBytes(): var unhashedKey:ByteArray = xorBytes(concatenatedPassword, salt); O operador XOR em nível de bits (^) retira dois valores uint e retorna um valor uint. (Um valor uint contém 32 bits.) Os valores de entrada enviados como argumentos para o método xorBytes() são uma String (a senha) e um ByteArray (o salt). Conseqüentemente, o código usa um loop para extrair 32 bits de uma vez de cada entrada para combinar usando o operador XOR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 206 Trabalhar com bancos de dados SQL locais private function xorBytes(passwordString:String, salt:ByteArray):ByteArray { var result:ByteArray = new ByteArray(); for (var i:uint = 0; i < 32; i += 4) { // ... } return result; } No loop, os primeiros 32 bits (4 bytes) são extraídos do parâmetro passwordString. Esses bits são extraídos e convertidos em um uint (o1) em um processo de duas partes. Primeiro, o método charCodeAt() obtém cada valor numérico do caractere. Depois, esse valor é desviado para a posição apropriada na unidade usando o operador de desvio à esquerda em nível de bits (<<) e o valor desviado é adicionado ao o1. Por exemplo, o primeiro caractere (i) se torna os primeiros 8 bits usando o operador de desvio à esquerda em nível de bits (<<) para desviar os bits deixados por 24 bits e atribuindo esse valor ao o1. O segundo caractere (i + 1) se torna os segundos 8 bits desviando seu valor 16 bits à esquerda e adicionando o resultado a o1. Os valores do terceiro e do quarto caracteres são adicionados da mesma forma. // ... // Extract 4 bytes from the password string and convert to a uint var o1:uint = passwordString.charCodeAt(i) << 24; o1 += passwordString.charCodeAt(i + 1) << 16; o1 += passwordString.charCodeAt(i + 2) << 8; o1 += passwordString.charCodeAt(i + 3); // ... A variável o1 agora contém 32 bits do parâmetro passwordString. Em seguida, 32 bits são extraídos do parâmetro salt, chamando seu método readUnsignedInt(). Os 32 bits são armazenados em uma variável uint o2. // ... salt.position = i; var o2:uint = salt.readUnsignedInt(); // ... Finalmente, os dois valores de 32 bits (uint) são combinados usando o operador XOR, e o resultado é gravado em um ByteArray chamado de result. // ... var xor:uint = o1 ^ o2; result.writeUnsignedInt(xor); // ... Quando o loop é concluído, o ByteArray contendo o resultado XOR é retornado. // ... } return result; } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 207 Trabalhar com bancos de dados SQL locais Hash da chave Após a senha concatenada e o salt serem combinados, a próxima etapa é oferecer proteção adicional a esse valor, fazendo hash dele por meio do algoritmo de hash SHA-256. O processo de hash dificulta para um invasor realizar a engenharia reversa no valor. Nesse ponto, o código tem um ByteArray chamado de unhashedKey, que contém a senha concatenada combinada com o salt. O projeto de biblioteca central (as3corelib) do ActionScript 3.0 inclui uma classe SHA256 no pacote com.adobe.crypto. O método SHA256.hashBytes(), que realiza um hash de SHA-256 em um ByteArray e retorna uma String contendo o resultado do hash de 256 bits como um número decimal. A classe EncryptionKeyGenerator usa a classe SHA256 para aplicar hash à chave: var hashedKey:String = SHA256.hashBytes(unhashedKey); Extrair a chave de criptografia do hash A chave de criptografia deve ser um ByteArray com exatamente 16 bytes (128 bits). O resultado do algoritmo de hash SHA-256 tem sempre 256 bits. Conseqüentemente, a etapa final é selecionar 128 bits do resultado com hash para usar como chave de criptografia real. Na classe EncryptionKeyGenerator, o código reduz a chave para 128 bits chamando o método generateEncryptionKey(). Em seguida, ele retorna esse resultado do método como o resultado do método getEncryptionKey(): var encryptionKey:ByteArray = generateEncryptionKey(hashedKey); return encryptionKey; É necessário usar os primeiros 128 bits como a chave de criptografia. Você pode selecionar um intervalo de bits iniciando em algum ponto arbitrário, pode selecionar todos os outros bits ou usar alguma outra maneira de selecionar bits. O importante é que o código selecione 128 bits diferentes e que os mesmos 128 bits sejam usados a cada vez. Nesse caso, o método generateEncryptionKey() usa o intervalo de bits que começa no 18º byte como a chave de criptografia. Como mencionado antes, a classe SHA256 retorna uma String contendo um hash de 256 bits como número hexadecimal. Um único bloco de 128 bits não tem muitos bytes a acrescentar a um ByteArray de uma vez. Conseqüentemente, o código usa um loop for para extrair caracteres da String hexadecimal, convertendo-os em valores numéricos reais e adicionando-os ao ByteArray. A String de resultado SHA-256 tem 64 caracteres. Um intervalo de 128 bits equivale a 32 caracteres na String, e cada caractere representa 4 bits. O menor incremento de dados que você pode adicionar a um ByteArray é um byte (8 bits), o que é equivalente a dois caracteres na String hash. Conseqüentemente, o loop conta de 0 a 31 (32 caracteres) em incrementos de 2 caracteres. Dentro do loop, o código determina primeiro a posição inicial do par de caracteres atual. Como o intervalo desejado começa na posição de indexação 17 (o 18º byte) do caractere, a variável position é atribuída ao valor iterador da corrente (i) mais 17. O código usa o método substr() do objeto da String para extrair os dois caracteres na posição atual. Esses caracteres são armazenados na variável hex. Em seguida, o código usa o método parseInt() para converter a String hex a um valor inteiro decimal. Ele armazena esse valor na variável byte. Finalmente, o código adiciona o valor de byte ao ByteArray result usando o método writeByte(). Quando o loop é concluído, o ByteArray result contém 16 bytes e está pronto para ser usado como chave de criptografia do banco de dados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 208 Trabalhar com bancos de dados SQL locais private function generateEncryptionKey(hash:String):ByteArray { var result:ByteArray = new ByteArray(); for (var i:uint = 0; i < 32; i += 2) { var position:uint = i + 17; var hex:String = hash.substr(position, 2); var byte:int = parseInt(hex, 16); result.writeByte(byte); } return result; } Exemplo completo de código para gerar e usar chave de criptografia A seguir há um exemplo completo de um código para a aplicação de “Geração e uso da chave de criptografia”. O código consiste em duas partes. O exemplo usa a classe EncryptionKeyGenerator para criar uma chave de criptografia a partir de uma senha. A classe EncryptionKeyGenerator está incluída no projeto de biblioteca central (as3corelib) do ActionScript 3.0 de códigofonte aberto. Você pode baixar o pacote as3corelib incluindo o código-fonte e a documentação. Você também pode baixar os arquivos SWC ou de código-fonte na página do projeto. O arquivo FLA do aplicativo contém o código fonte de um aplicativo simples que cria ou abre uma conexão para um banco de dados criptografado. O arquivo FLA tem quatro componentes colocados no palco: Nome da ocorrência Tipo do componente Descrição instruções Label Contém as instruções fornecidas ao usuário passwordInput TextInput Campo de entrada onde o usuário digita a senha openButton Button Botão em que o usuário clica após digitar a senha statusMsg Label Exibe mensagens de status (êxito ou falha) O código do aplicativo é definido em um quadro-chave no quadro 1 da linha do tempo principal. Este é o código do aplicativo: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 209 Trabalhar com bancos de dados SQL locais import com.adobe.air.crypto.EncryptionKeyGenerator; const dbFileName:String = "encryptedDatabase.db"; var dbFile:File; var createNewDB:Boolean = true; var conn:SQLConnection; init(); // ------- Event handling ------function init():void { passwordInput.displayAsPassword = true; openButton.addEventListener(MouseEvent.CLICK, openConnection); statusMsg.setStyle("textFormat", new TextFormat(null, null, 0x990000)); conn = new SQLConnection(); dbFile = File.applicationStorageDirectory.resolvePath(dbFileName); if (dbFile.exists) { createNewDB = false; instructions.text = "Enter your database password to open the encrypted database."; openButton.label = "Open Database"; } else { instructions.text = "Enter a password to create an encrypted database. The next time you open the application, you will need to re-enter the password to open the database again."; openButton.label = "Create Database"; } } function openConnection(event:MouseEvent):void { var keyGenerator:EncryptionKeyGenerator = new EncryptionKeyGenerator(); var password:String = passwordInput.text; if (password == null || password.length <= 0) { statusMsg.text = "Please specify a password."; return; } if (!keyGenerator.validateStrongPassword(password)) { statusMsg.text = "The password must be 8-32 characters long. It must contain at least one lowercase letter, at least one uppercase letter, and at least one number or symbol."; return; } passwordInput.text = ""; passwordInput.enabled = false; openButton.enabled = false; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 210 Trabalhar com bancos de dados SQL locais var encryptionKey:ByteArray = keyGenerator.getEncryptionKey(password); conn.addEventListener(SQLEvent.OPEN, openHandler); conn.addEventListener(SQLErrorEvent.ERROR, openError); conn.openAsync(dbFile, SQLMode.CREATE, null, false, 1024, encryptionKey); } function openHandler(event:SQLEvent):void { conn.removeEventListener(SQLEvent.OPEN, openHandler); conn.removeEventListener(SQLErrorEvent.ERROR, openError); statusMsg.setStyle("textFormat", new TextFormat(null, null, 0x009900)); if (createNewDB) { statusMsg.text = "The encrypted database was created successfully."; } else { statusMsg.text = "The encrypted database was opened successfully."; } } function openError(event:SQLErrorEvent):void { conn.removeEventListener(SQLEvent.OPEN, openHandler); conn.removeEventListener(SQLErrorEvent.ERROR, openError); if (!createNewDB && event.error.errorID == EncryptionKeyGenerator.ENCRYPTED_DB_PASSWORD_ERROR_ID) { statusMsg.text = "Incorrect password!"; } else { statusMsg.text = "Error creating or opening database."; } } Estratégias para trabalhar com bancos de dados SQL Existem várias maneiras pelas quais um aplicativo pode acessar e trabalhar com um banco de dados SQL local. O design do aplicativo pode variar em termos de como seu código é organizado, a seqüência e o intervalo de execução das operações, e assim por diante. As técnicas que você escolhe podem afetar a facilidade com que o aplicativo é desenvolvido. Elas podem afetar a facilidade com que você modificará o aplicativo em futuras atualizações. Elas também podem afetar o desempenho do aplicativo do ponto de vista dos usuários. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 211 Trabalhar com bancos de dados SQL locais Distribuição de um banco de dados previamente preenchido Quando você usa um banco de dados SQL local do AIR no seu aplicativo, este espera um banco de dados com uma certa estrutura de tabelas, colunas e assim por diante. Alguns aplicativos também esperam que certos dados estejam previamente preenchidos no arquivo de banco de dados. Uma forma de assegurar que o banco de dados tenha a estrutura apropriada é criar um banco de dados no código do aplicativo. Quando o aplicativo é carregado, ele verifica se o arquivo de banco de dados correspondente existe em um determinado local. Se o arquivo não existir, o aplicativo executará um conjunto de comandos para criar o arquivo de banco de dados, criar a estrutura do banco de dados e preencher as tabelas com os dados iniciais. O código que cria o banco de dados e suas tabelas geralmente é complexo. Com freqüência, ele só é usado uma vez durante o período em que o aplicativo fica instalado, mas ainda assim aumenta o tamanho e a complexidade do aplicativo. Como alternativa à criação do banco de dados, da estrutura e dos dados de modo programático, você pode distribuir um banco de dados previamente preenchido com o aplicativo. Para distribuir um banco de dados predefinido, inclua o arquivo correspondente no pacote AIR do aplicativo. Como todos os arquivos que são incluídos em um pacote AIR, um arquivo de banco de dados compactado é instalado no diretório do aplicativo (o diretório representado pela propriedade File.applicationDirectory). No entanto, os arquivos desse diretório são somente leitura. Use o arquivo do pacote AIR como um banco de dados “modelo”. Na primeira vez que um usuário executar o aplicativo, copie o arquivo de banco de dados original para o diretório de armazenamento do aplicativo do usuário (ou outro local) e use esse banco de dados no aplicativo. Aperfeiçoamento do desempenho do banco de dados Várias técnicas incorporadas ao Adobe AIR permitem melhorar o desempenho de operações de banco de dados em seu aplicativo. Além das técnicas descritas aqui, a forma como uma instrução SQL é criada também pode afetar o desempenho do banco de dados. Com freqüência, existem diversas maneiras de criar uma instrução SQL SELECT para recuperar um conjunto de resultados específico. Em alguns casos, as diferentes abordagens exigem mais ou menos trabalho da parte do mecanismo de banco de dados. Este aspecto de se aprimorar o desempenho do banco de dados (criando instruções SQL que proporcionem melhor desempenho) não é abordado na documentação do Adobe AIR. Use uma ocorrência de SQLStatement para cada instrução SQL Antes de qualquer instrução SQL ser executada, o tempo de execução a prepara (compila) para determinar as etapas realizadas internamente para executar a instrução. Quando você chama SQLStatement.execute() em uma ocorrência de SQLStatement que não foi executada anteriormente, a instrução é preparada de forma automática antes de ser executada. Nas chamadas subseqüentes do método execute(), desde que a propriedade SQLStatement.text não tenha sido alterada, a instrução ainda será preparada. Como resultado, ela será executada mais rapidamente. Para aproveitar ao máximo a capacidade de reutilizar instruções, se for necessário alterar valores entre as execuções de uma instrução, utilize parâmetros de instrução para personalizar a sua instrução. (Os parâmetros de instrução são especificados através da propriedade de matriz associativa SQLStatement.parameters.) Diferentemente de quando se altera a propriedade text da ocorrência de SQLStatement, se você alterar os valores de parâmetros de instrução, o tempo de execução não terá de preparar a instrução novamente. Para obter mais informações sobre como usar parâmetros em instruções, consulte “Uso de parâmetros em instruções” na página 175. Preparar e executar uma instrução pode ser uma operação trabalhosa, por isso uma boa estratégia é pré-carregar os dados iniciais e então executar outras instruções em segundo plano. Carregue os dados de que o aplicativo precisa primeiro. Quando as primeiras operações de inicialização do aplicativo forem concluídas, ou durante algum período de “inatividade” no aplicativo, execute outras instruções. Por exemplo, se o aplicativo não acessa o banco de dados para exibir a tela inicial, aguarde até que essa tela seja exibida, abra a conexão com o banco de dados e, então, crie as DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 212 Trabalhar com bancos de dados SQL locais ocorrências de SQLStatement e execute qualquer uma delas. Como alternativa, suponha que, quando o seu aplicativo é inicializado, ele imediatamente exibe alguns dados, como o resultado de uma determinada consulta. Nesse caso, vá em frente e execute a ocorrência de SQLStatement referente a essa consulta. Depois que os dados iniciais forem carregados e exibidos, crie ocorrências de SQLStatement para outras operações de banco de dados e, se possível, execute outras instruções que serão necessárias posteriormente. Quando você reutiliza uma ocorrência de SQLStatement, o aplicativo precisa manter uma referência à ocorrência de SQLStatement depois que ela foi preparada. Para isso, declare a variável como uma variável com escopo de classe e não como uma variável com escopo de função. Uma boa maneira de fazer isso é estruturar o aplicativo para que a instrução SQL seja colocada em uma única classe. Um grupo de instruções que são executadas em combinação também pode ser colocado em uma única classe. Se você definir a(s) ocorrência(s) de SQLStatement como variáveis de membro da classe, elas persistirão desde que a ocorrência da classe wrapper exista no aplicativo. No mínimo, basta definir uma variável que contenha a ocorrência de SQLStatement fora de uma função para que a ocorrência persista na memória. Por exemplo, declare a ocorrência de SQLStatement como variável de membro em uma classe do ActionScript ou como variável não-função em um arquivo JavaScript. Em seguida, você pode definir os valores de parâmetro da instrução e chamar o método execute() correspondente quando quiser executar a consulta. Agrupamento de várias operações em uma transação Suponha que você está executando muitas instruções SQL que envolvem a inclusão ou a alteração de dados (instruçõesINSERT ou UPDATE). Você pode conseguir um aumento de desempenho considerável se executar todas as instruções em uma transação explícita. Se você não iniciar uma transação de forma explícita, cada uma das instruções será executada em sua própria transação criada automaticamente. Depois que a execução de cada transação (cada instrução) for concluída, o tempo de execução gravará os dados resultantes no arquivo de banco de dados do disco. Por outro lado, pense no que acontece se você cria uma transação explicitamente e executa as instruções no contexto dessa transação. O tempo de execução faz todas as alterações na memória e, depois, grava todas as alterações no arquivo de banco de dados de uma só vez quando a transação é confirmada. Gravar dados em disco normalmente é a parte mais demorada da operação. Como conseqüência, gravar no disco de uma só vez e não uma vez por instrução SQL pode melhorar o desempenho significativamente. Minimizar o processamento do tempo de execução O uso das seguintes técnicas pode evitar trabalho desnecessário por parte do mecanismo de banco de dados e melhorar o desempenho dos aplicativos: • Sempre especifique os nomes de banco de dados explicitamente junto com os nomes de tabela em uma instrução. (Use “main” se for o banco de dados principal). Por exemplo, use SELECT employeeId FROM main.employees em vez de SELECT employeeId FROM employees. Quando você especifica o nome do banco de dados de maneira explícita, evita que o tempo de execução tenha de verificar cada banco de dados para encontrar a tabela correspondente. Isso também evita a possibilidade de o tempo de execução escolher o banco de dados errado. Siga esta regra mesmo que um SQLConnection esteja conectado a apenas um banco de dados, porque em segundo plano o SQLConnection também está conectado a um banco de dados temporário que pode ser acessado através de instruções SQL. • Sempre especifique os nomes de coluna explicitamente em uma instrução SELECT ou INSERT. • Divida as linhas retornadas por uma instrução SELECT que recupera um número grande de linhas: consulte “Recuperação dos resultados de SELECT em partes” na página 182. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 213 Trabalhar com bancos de dados SQL locais Evite alterações em esquemas Se possível, evite alterar o esquema (estrutura de tabelas) de um banco de dados depois de adicionar dados às tabelas. Normalmente, um arquivo de banco de dados é estruturado com as definições de tabela no início do arquivo. Quando você abre uma conexão com um banco de dados, o tempo de execução carrega essas definições. Quando você adiciona dados a tabelas de um banco de dados, eles são adicionados ao arquivo após os dados de definição de tabela. Entretanto, se você fizer alterações no esquema, como adicionar uma coluna a uma tabela ou adicionar uma nova tabela, os novos dados de definição de tabela serão combinados com os dados de tabela no arquivo de banco de dados. Se os dados de definição de tabela não estiverem todos no início do arquivo de banco de dados, demorará mais para abrir uma conexão com o banco de dados, pois o tempo de execução lê esses dados de diferentes partes do arquivo. Caso você não precise fazer alterações no esquema, poderá chamar o método SQLConnection.compact() depois de concluir as alterações. Esta operação reestrutura o arquivo de banco de dados para que os dados de definição de tabela fiquem localizados juntos no início do arquivo. No entanto, a operação compact() pode ser demorada, principalmente quando um arquivo de banco de dados aumenta de tamanho. Práticas recomendadas de trabalho com bancos de dados SQL locais A lista a seguir é um conjunto de técnicas sugeridas que você pode usar para melhorar o desempenho, a segurança e a facilidade de manutenção dos seus aplicativos quando trabalhar com bancos de dados SQL locais. Para conhecer outras técnicas para aprimorar aplicativos de banco de dados, consulte “Aperfeiçoamento do desempenho do banco de dados” na página 211. Crie conexões de banco de dados previamente Mesmo que o seu aplicativo não execute nenhuma instrução quando inicialmente carregado, instancie um objeto SQLConnection e chame o método open() ou openAsync() correspondente com antecedência (por exemplo, após a inicialização do aplicativo) para evitar atrasos na execução de instruções. Consulte “Conexão com um banco de dados” na página 172. Reutilize conexões de banco de dados Se você acessa um certo banco de dados ao longo da execução do seu aplicativo, mantenha uma referência à ocorrência de SQLConnection e a reutilize no aplicativo inteiro em vez de fechar e reabrir a conexão. Consulte “Conexão com um banco de dados” na página 172. Dê preferência ao modo de execução assíncrona Quando criamos um código de acesso a dados, pode ser tentador executar operações de maneira síncrona em vez de assíncrona, porque usar operações síncronas geralmente requer um código mais curto e menos complexo. Porém, conforme descrito na seção “Uso de operações de banco de dados síncronas e assíncronas” na página 190, as operações síncronas podem ter um impacto no desempenho que é óbvio para os usuários e prejudicial para a experiência deles no aplicativo. O tempo usado para uma única operação varia conforme a operação e, principalmente, o volume de dados envolvido. Por exemplo, uma instrução SQL INSERT que só adiciona uma linha ao banco de dados demora menos tempo do que uma instrução SELECT que recupera milhares de linhas de dados. No entanto, quando você usa a execução síncrona para realizar várias operações, as operações normalmente são encadeadas. Mesmo que o tempo que cada operação leve seja muito curto, o aplicativo fica congelado até a conclusão de todas as operações síncronas. Por isso, o tempo acumulado de várias operações encadeadas pode ser suficiente para paralisar o aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 214 Trabalhar com bancos de dados SQL locais Use operações assíncronas como uma abordagem padrão, principalmente no caso de operações que envolvem um grande número de linhas. Há uma técnica para dividir o processamento de grandes conjuntos de resultados de instruções SELECT, descrita em “Recuperação dos resultados de SELECT em partes” na página 182. No entanto, ela só pode ser usada no modo de execução assíncrona. Utilize operações síncronas apenas quando não conseguir obter uma certa funcionalidade usando programação assíncrona, quando tiver considerado as vantagens e desvantagens para os usuários do aplicativo em termos de desempenho e quando testar o aplicativo e perceber que o desempenho foi afetado. O uso da execução assíncrona pode envolver uma codificação mais complexa. Porém, lembre-se de que você só precisa criar o código uma vez, mas que os usuários do aplicativo têm de usá-lo repetidas vezes, de forma ágil ou lentamente. Em muitos casos, usando uma ocorrência de SQLStatement à parte para cada instrução SQL a ser executada, é possível enfileirar várias operações SQL de uma só vez, o que torna o código assíncrono parecido com o código síncrono quanto à maneira como ele é criado. Para obter mais informações, consulte “Noções básicas sobre o modelo de execução assíncrona” na página 193. Use instruções SQL separadas e não altere a propriedade text de SQLStatement Para qualquer instrução SQL executada mais de uma vez em um aplicativo, crie uma ocorrência de SQLStatement à parte para cada instrução SQL. Use essa ocorrência de SQLStatement sempre que esse comando SQL for executado. Por exemplo, suponha que você está criando um aplicativo que inclui quatro operações SQL diferentes executadas várias vezes. Nesse caso, crie quatro ocorrências separadas de SQLStatement e chame o método execute() de cada instrução para executá-la. Evite a alternativa de usar uma única ocorrência de SQLStatement para todas as instruções SQL, sempre redefinindo sua propriedade text antes de executar a instrução. Consulte “Use uma ocorrência de SQLStatement para cada instrução SQL” na página 211 para obter mais informações. Use parâmetros de instrução Use parâmetros SQLStatement — nunca concatene a entrada do usuário no texto da instrução. O uso de parâmetros torna o seu aplicativo mais seguro porque impede a possibilidade de ataques de injeção SQL. Isso permite usar objetos em consultas (e não apenas valores literais SQL). Também torna a execução das instruções mais eficiente, porque elas podem ser reutilizadas sem que você precise recompilá-las todas as vezes que forem executadas. Consulte “Uso de parâmetros em instruções” na página 175 para obter mais informações. Use restrições para nomes de colunas e de parâmetros Quando você não especifica uma classe itemClass para um SQLStatement, para evitar erros de ortografia, defina constantes String que contenham os nomes das colunas de uma tabela. Use essas constantes no texto da instrução e para os nomes de propriedade quando recuperar valores dos objetos resultantes. Também use constantes para os nomes de parâmetros. 215 Capítulo 19: Armazenamento de dados criptografados O tempo de execução do Adobe® AIR™ fornece um armazenamento local criptografado persistente para cada aplicativo do AIR instalado no computador de um usuário. Isso permite que você salve e recupere dados armazenados no disco rígido local do usuário em um formato criptografado que não possa ser facilmente decifrado por outros aplicativos ou usuários. Um armazenamento local criptografado separado é usado para cada aplicativo do AIR, e cada aplicativo do AIR usa um armazenamento local criptografado separado para cada usuário. Nota: Além do armazenamento local criptografado, o AIR também fornece criptografia para conteúdo armazenado em bancos de dados do SQL. Para obter detalhes, consulte “Uso da criptografia com bancos de dados SQL” na página 194. Você pode querer usar o armazenamento local criptografado para armazenar informações que devem ser protegidas, como credenciais de login para serviços da Web. O AIR usa o DPAPI no Windows, o KeyChain no Mac OS e o KeyRing ou KWallet no Linux para associar o armazenamento local criptografado a cada aplicativo e usuário. O armazenamento local criptografado usa a criptografia AES-CBC de 128 bits. As informações no armazenamento local criptografado estão disponíveis apenas a conteúdo de aplicativos do AIR na caixa de proteção de segurança do aplicativo. Use os métodos estáticos setItem() e removeItem() da classe EncryptedLocalStore para armazenar e recuperar dados do armazenamento local. Os dados são armazenados em uma tabela de hash, usando seqüências de caracteres como chaves, com os dados armazenados como matrizes de bytes. Por exemplo, o código a seguir armazena uma seqüência de caracteres no armazenamento local criptografado: var str:String = "Bob"; var bytes:ByteArray = new ByteArray(); bytes.writeUTFBytes(str); EncryptedLocalStore.setItem("firstName", bytes); var storedValue:ByteArray = EncryptedLocalStore.getItem("firstName"); trace(storedValue.readUTFBytes(storedValue.length)); // "Bob" O terceiro parâmetro do método setItem(), o parâmetro stronglyBound, é opcional. Quando esse parâmetro é definido como true, o armazenamento local criptografado fornece um nível mais alto de segurança, ligando o item armazenado aos bits e à assinatura digital do aplicativo do AIR de armazenamento, bem como à ID do editor do aplicativo quando: var str:String = "Bob"; var bytes:ByteArray = new ByteArray(); bytes.writeUTFBytes(str); EncryptedLocalStore.setItem("firstName", bytes, true); Para um item armazenado com stronglyBound definido como true, as chamadas subseqüentes a getItem() apenas são bem-sucedidas se o aplicativo do AIR de chamada for idêntico ao aplicativo de armazenamento (se nenhum dado nos arquivos do diretório do aplicativo tiver sido alterado). Se o aplicativo do AIR de chamada for diferente do aplicativo de armazenamento, o aplicativo lançará uma exceção de erro quando você chamar getItem() para um item fortemente ligado. Se você atualizar seu aplicativo, ele não será capaz de ler os dados fortemente ligados previamente gravados no armazenamento local criptografado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 216 Armazenamento de dados criptografados Por padrão, um aplicativo do AIR não consegue ler o armazenamento local criptografado de outro aplicativo. A definição stronglyBound fornece ligação extra (aos dados nos bits do aplicativo) para impedir que um aplicativo invasor tente ler o armazenamento local criptografado de seu aplicativo apoderando-se da ID do editor do aplicativo. Se você atualizar um aplicativo para usar um certificado de assinatura diferente (usando uma assinatura de migração), a versão atualizada não poderá acessar nenhum dos itens no armazenamento original, mesmo se o parâmetro stronglyBound foi definido como falso. Para obter mais informações, consulte “Alteração de certificados” na página 325. Você pode excluir um valor do armazenamento local criptografado usando o método EncryptedLocalStore.removeItem(), como no seguinte exemplo: EncryptedLocalStore.removeItem("firstName"); Você pode limpar todos os dados do armazenamento local criptografado chamando o método EncryptedLocalStore.reset(), como no seguinte exemplo: EncryptedLocalStore.reset(); Ao depurar um aplicativo no ADL (AIR Debug Launcher), o aplicativo usa um armazenamento local criptografado diferente do que é usado na versão instalada do aplicativo. O armazenamento local criptografado poderá ficar mais lento se os dados armazenados excederem 10 MB. Quando você desinstala um aplicativo do AIR, o desinstalador não exclui os dados armazenados no armazenamento local criptografado. Os dados do armazenamento local criptografado são colocados em um subdiretório do diretório de dados do aplicativo do usuário; o caminho do subdiretório é Adobe/AIR/ELS/ seguindo da ID do aplicativo. 217 Capítulo 20: Sobre o ambiente HTML O Adobe®AIR™ usa WebKit (www.webkit.org), também usado pelo navegador da Web Safari, para analisar, alterar o layout e processar conteúdo HTML e JavaScript. Usar as APIs do AIR em conteúdo HTML é opcional. Você pode programar no conteúdo de um objeto HTMLLoader ou janela HTML inteiramente com HTML e JavaScript. A maioria dos aplicativos e páginas HTML existentes deve ser executada com algumas alterações (supondo que eles usam recursos HTML, CSS, DOM e JavaScript compatíveis com WebKit). Como aplicativos AIR são executados diretamente na área de trabalho, com acesso completo ao sistema de arquivos, o modelo de segurança para conteúdo HTML é mais rigoroso que o modelo de segurança de um navegador da Web típico. No AIR, apenas o conteúdo carregado do diretório de instalação do aplicativo é colocado na caixa de proteção do aplicativo. A caixa de proteção do aplicativo tem o nível mais alto de privilégio e permite acesso às APIs do AIR. O AIR coloca outro conteúdo em caixas de proteção isoladas com base na origem do conteúdo. Arquivos carregados do sistema de arquivos entram em uma caixa de proteção local. Arquivos carregados da rede usando os protocolos http: ou https: entram em uma caixa de proteção baseada no domínio do servidor remoto. O conteúdo nessas caixas de proteção que não são de aplicativo não pode acessar nenhuma API do AIR e é executado da mesma forma que em um navegador da Web típico. O AIR usa WebKit (www.webkit.org), também usado pelo navegador da Web Safari, para analisar, alterar o layout e processar conteúdo HTML e JavaScript. As classes e objetos de host incorporados do AIR fornecem uma API para recursos tradicionalmente associados a aplicativos de área de trabalho. Tais recursos incluem ler e escrever arquivos e gerenciar janelas. O Adobe AIR também herda APIs do Adobe® Flash® Player, o que inclui recursos como soquetes binários e de som. O conteúdo HTML no AIR não exibe conteúdo SWF ou PDF se as configurações de alfa, dimensionamento ou transparência forem aplicadas. Para obter mais informações, consulte Considerações ao carregar conteúdo SWF ou PDF em uma página HTML e “Transparência de janelas” na página 63. Visão geral do ambiente HTML O Adobe AIR fornece um ambiente JavaScript completo do tipo de navegador com um processador de HTML, um modelo de objeto de documento e um intérprete do JavaScript. O ambiente JavaScript é representado pela classe HTMLLoader do AIR. Em janelas HTML, um objeto HTMLLoader contém todo o conteúdo HTML e está, por sua vez, contido em um objeto NativeWindow. Em conteúdo SWF, a classe HTMLLoader, que estende a classe Sprite, pode ser adicionada à lista de exibição de um estágio como qualquer outro objeto de exibição. As propriedades do ActionScript™ da classe são descritas em “Gravação de script de contêiner HTML” na página 258 e também na Referência de linguagem do ActionScript do Flex 3. Sobre o ambiente JavaScript e seu relacionamento com o AIR O diagrama a seguir ilustra o relacionamento entre o ambiente JavaScript e o ambiente de tempo de execução do AIR. Embora apenas uma única janela nativa seja exibida, um aplicativo AIR pode conter várias janelas. (E uma única janela pode conter vários objetos HTMLLoader.) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 218 Sobre o ambiente HTML Ambiente de tempo de execução do AIR NativeWindow HTMLLoader janela Ambiente do JavaScript janela janela corpo cabeçalho htmlLoader native4Window tempo de execução h1 div table p O ambiente JavaScript possui seus próprios objetos Document e Window. O código JavaScript pode interagir com o ambiente de tempo de execução do AIR por meio das propriedades runtime, nativeWindow e htmlLoader. O código ActionScript pode interagir com o ambiente JavaScript pela propriedade window de um objeto HTMLLoader, que é uma referência ao objeto Window do JavaScript. Além disso, os objetos ActionScript e JavaScript podem ouvir eventos despachados por objetos AIR e JavaScript. A propriedade runtime fornece acesso a classes API do AIR, permitindo que você crie novos objetos do AIR, bem como membros de classe de acesso (também chamados estáticos). Para acessar uma API do AIR, você adiciona o nome da classe, com pacote, à propriedade runtime. Por exemplo, para criar um objeto File, você usaria a instrução: var file = new window.runtime.filesystem.File(); Nota: O SDK do AIR fornece um arquivo JavaScript, AIRAliases.js, que define aliases mais convenientes para as classes do AIR usadas mais comumente. Quando você importa esse arquivo, pode usar a forma mais curta air.Class em vez de window.runtime.package.Class. Por exemplo, você poderia criar o objeto File com new air.File(). O objeto NativeWindow fornece propriedades para controlar a janela da área de trabalho. De uma página HTML, você pode acessar o objeto NativeWindow contido com a propriedade window.nativeWindow. O objeto HTMLLoader fornece propriedades, métodos e eventos para controlar como o conteúdo é carregado e processado. De uma página HTML, você pode acessar o objeto HTMLLoader pai com a propriedade window.htmlLoader. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 219 Sobre o ambiente HTML Importante: Apenas páginas instaladas como parte de um aplicativo possuem as propriedades htmlLoader, nativeWindow ou runtime e apenas quando carregadas como o documento de nível superior. Essas propriedades não são adicionadas quando um documento é carregado em um frame ou iframe. (Um documento filho pode acessar essas propriedades no documento pai desde que ele esteja na mesma caixa de proteção de segurança. Por exemplo, um documento carregado em um frame poderia acessar a propriedade runtime de seu pai com parent.runtime.) Sobre a segurança O AIR executa todos os códigos em uma caixa de proteção de segurança baseada no domínio de origem. O conteúdo do aplicativo, limitado ao conteúdo carregado do diretório de instalação do aplicativo, é colocado na caixa de proteção do aplicativo. O acesso ao ambiente de tempo de execução e às APIs do AIR está disponível apenas para HTML e JavaScript em execução nessa caixa de proteção. Ao mesmo tempo, a maior parte da execução e avaliação dinâmica de JavaScript é bloqueada na caixa de proteção do aplicativo após todos os manipuladores da página de evento load terem sido retornados. Você pode mapear uma página de aplicativo em uma caixa de proteção que não seja de aplicativo carregando a página em um frame ou iframe e definindo os atributos sandboxRoot e documentRoot específicos do AIR do frame. Definindo o valor sandboxRoot para um domínio remoto real, você pode habilitar o conteúdo da caixa de proteção para cruzar conteúdo de scripts nesse domínio. Mapear páginas dessa maneira pode ser útil ao carregar e fazer o script de conteúdo remoto, como em um aplicativo mash-up. Outra maneira de permitir que o conteúdo de aplicativo e que não é de aplicativo cruze scripts entre si, e a única maneira de fornecer acesso a conteúdo de não-aplicativo às APIs do AIR, é criar uma ponte de caixa de proteção. Uma ponte pai-para-filho permite conteúdo em um frame filho, iframe ou window para acessar métodos designados e propriedades definidas na caixa de proteção do aplicativo. Por outro lado, uma ponte filho-para-pai permite que conteúdo de aplicativo acesse métodos e propriedades designadas definidas na caixa de proteção do filho. As pontes de caixa de proteção são estabelecidas pela definição das propriedades parentSandboxBridge e childSandboxBridge do objeto window. Para obter mais informações, consulte “segurança HTML” na página 30 e “Elementos HTML frame e iframe” na página 227. Sobre plug-ins e objetos incorporados O AIR suporta o plug-in do Adobe® Acrobat®. Os usuários devem ter o Acrobat ou Adobe® Reader® 8.1 (ou superior) para exibir conteúdo PDF. O objeto HTMLLoader fornece uma propriedade para verificar se o sistema de um usuário pode exibir PDF. O conteúdo de arquivo SWF também pode ser exibido no ambiente HTML, mas esse recurso é incorporado ao AIR e não usa um plug-in externo. Nenhum outro plug-in de Webkit é suportado no AIR. Consulte também “segurança HTML” na página 30 “Caixas de proteção HTML” na página 220 “Elementos HTML frame e iframe” na página 227 “Objeto Window do JavaScript” na página 226 “O objeto XMLHttpRequest” na página 221 “Adição de conteúdo em PDF” na página 272 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 220 Sobre o ambiente HTML Extensões do AIR e Webkit O Adobe AIR usa o mecanismo do Webkit de código aberto, também usado no navegador da Web Safari. O AIR adiciona várias extensões para permitir acesso às classes e objetos runtime, bem como à segurança. Além disso, o Webkit por si só adiciona recursos não incluídos nos padrões da W3C para HTML, CSS e JavaScript. Apenas as adições do AIR e as extensões do Webkit mais dignas de nota são tratadas aqui. Para obter uma documentação adicional sobre HTML não-padrão, CSS e JavaScript, consulte www.webkit.org e developer.apple.com. Para obter informações sobre padrões, consulte o site da W3C . O Mozilla também fornece uma referência geral valiosa sobre tópicos HTML, CSS e DOM (é claro que os mecanismos do Webkit e Mozilla não são idênticos). Nota: O AIR não suporta os seguintes recursos do WebKit padrão e estendidos: o método print() do objeto Window do JavaScript; plug-ins, exceto Acrobat ou Adobe Reader 8.1+; SVG (gráficos vetoriais escaláveis), a propriedade opacity do CSS. JavaScript no AIR O AIR faz várias alterações no comportamento típico de objetos JavaScript comuns. Várias dessas alterações são feitas para tornar fácil escrever aplicativos seguros no AIR. Ao mesmo tempo, essas diferenças em comportamento significam que alguns padrões de codificação JavaScript comuns, e aplicativos Web existentes usando esses padrões, nem sempre podem executar conforme esperado no AIR. Para obter informações sobre como corrigir esses tipos de problemas, consulte “Como evitar erros JavaScript relacionados à segurança” na página 235. Caixas de proteção HTML O AIR coloca conteúdo em caixas de proteção isoladas de acordo com a origem do conteúdo. As regras da caixa de proteção são consistentes com a política de mesma origem implementada pela maioria dos navegadores da Web, bem como as regras para caixas de proteção implementadas pelo Adobe Flash Player. Além disso, o AIR fornece um novo tipo de caixa de proteção do aplicativo para conter e proteger conteúdo do aplicativo. Consulte “Caixas de proteção” na página 27 para obter mais informações sobre os tipos de caixas de proteção que você pode encontrar ao desenvolver aplicativos AIR. O acesso ao ambiente de tempo de execução e às APIs do AIR está disponível apenas para HTML e JavaScript em execução na caixa de proteção do aplicativo. Ao mesmo tempo, no entanto, a execução e avaliação dinâmica de JavaScript, em suas várias formas, são amplamente restritas na caixa de proteção do aplicativo por razões de segurança. Essas restrições são adequadas quer seu aplicativo realmente carregue ou não informações diretamente de um servidor. (Até mesmo conteúdo de arquivo, seqüências de caracteres coladas e entrada do usuário direta podem ser incertos.) A origem do conteúdo em uma página determina a caixa de proteção à qual ele é consignado. Apenas o conteúdo carregado do diretório do aplicativo (o diretório de instalação referenciado pelo app: esquema de URL) é colocado na caixa de proteção do aplicativo. O conteúdo carregado do sistema de arquivos é colocado na caixa de proteção local com sistema de arquivos ou confiável local, que permite acesso e interação com conteúdo no sistema de arquivos local, mas não conteúdo remoto. O conteúdo carregado da rede é colocado em uma caixa de proteção remota correspondente ao seu domínio de origem. Para permitir que uma página de aplicativo interaja livremente com o conteúdo em uma caixa de proteção remota, a página pode ser mapeada para o mesmo domínio do conteúdo remoto. Por exemplo, se você escreve um aplicativo que exibe dados de mapas de um serviço de Internet, a página do seu aplicativo que carrega e exibe conteúdo do serviço poderia ser mapeada para o domínio de serviço. Os atributos para mapear páginas em um domínio e uma caixa de proteção remota são novos atributos adicionados aos elementos HTML frame e iframe. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 221 Sobre o ambiente HTML Para permitir conteúdo em uma caixa de proteção que não seja de aplicativo para usar com segurança recursos do AIR, você pode configurar uma ponte de caixa de proteção pai. Para permitir que o conteúdo de aplicativo chame com segurança métodos e acesse propriedades de conteúdo em outras caixas de proteção, você pode configurar uma ponte de caixa de proteção filha. Segurança aqui significa que o conteúdo remoto não pode obter acidentalmente referências a objetos, propriedades ou métodos que não são expostos explicitamente. Apenas tipos de dados simples, funções e objetos anônimos podem ser transmitidos pela ponte. No entanto, você ainda deve evitar expor explicitamente funções potencialmente perigosas. Se, por exemplo, você expôs uma interface que permitiu ao conteúdo remoto ler e escrever arquivos em qualquer lugar no sistema de um usuário, você pode estar fornecendo ao conteúdo remoto o meio para fazer um dano considerável aos seus usuários. Função eval() do JavaScript O uso da função eval() é restrito à caixa de proteção do aplicativo depois que o carregamento de uma página tiver sido concluído. Alguns usos são permitidos para que dados formatados por JSON possam ser analisados com segurança, mas qualquer avaliação que resulte em instruções executáveis terá como conseqüência um erro. O capítulo “Restrições de código de conteúdo em caixas de proteção distintas” na página 32 descreve os usos permitidos da função eval(). Construtores de funções Na caixa de proteção do aplicativo, os construtores de funções podem ser usados antes que o carregamento de uma página tenha sido concluído. Após todos os manipuladores de eventos load da página terem sido concluídos, novas funções não podem ser criadas. Carregamento de scripts externos As páginas HTML na caixa de proteção do aplicativo não podem usar a tag de script para carregar arquivos de JavaScript de fora do diretório do aplicativo. Para uma página no seu aplicativo carregar um script de fora do diretório do aplicativo, a página deve ser mapeada para uma caixa de proteção que não seja de aplicativo. O objeto XMLHttpRequest O AIR fornece um objeto XMLHttpRequest (XHR) que os aplicativos podem usar para fazer solicitações de dados. O exemplo a seguir ilustra uma solicitação de dados simples: xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", "http:/www.example.com/file.data", true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { //do something with data... } } xmlhttp.send(null); Em contraste com um navegador, o AIR permite que o conteúdo em execução na caixa de proteção do aplicativo solicite dados de qualquer domínio. O resultado de um XHR que contém uma seqüência de caracteres JSON pode ser avaliado em objetos de dados, a menos que o resultado também contenha código executável. Se instruções executáveis estão presentes no resultado de XHR, um erro é lançado e a tentativa de avaliação falha. Para impedir a injeção acidental de código de fontes remotas, os XHRs síncronos retornam um resultado vazio se feito antes que o carregamento de uma página seja concluído. Os XHRs assíncronos sempre são retornados após o carregamento de uma página. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 222 Sobre o ambiente HTML Por padrão, o AIR bloqueia XMLHttpRequests entre vários domínios em caixas de proteção de não-aplicativos. Uma janela pai na caixa de proteção do aplicativo pode optar por permitir solicitações entre domínios em um frame filho com conteúdo em uma caixa de proteção que não seja de aplicativo definindo allowCrossDomainXHR, um atributo adicionado pelo AIR, como true no elemento frame ou iframe contido: <iframe id="mashup" src="http://www.example.com/map.html" allowCrossDomainXHR="true" </iframe> Nota: Quando conveniente, a classe URLStream do AIR também pode ser usada para fazer o download de dados. Se você despachar um XMLHttpRequest para um servidor remoto de um frame ou iframe contendo conteúdo de aplicativo que tenha sido mapeado para uma caixa de proteção remota, verifique se a URL de mapeamento não mascara o endereço do servidor usado no XHR. Por exemplo, considere a seguinte definição de iframe, que mapeia conteúdo de aplicativo em uma caixa de proteção remota para o domínio example.com: <iframe id="mashup" src="http://www.example.com/map.html" documentRoot="app:/sandbox/" sandboxRoot="http://www.example.com/" allowCrossDomainXHR="true" </iframe> Como o atributo sandboxRoot remapeia a URL raiz do endereço www.example.com, todas as solicitações são carregadas do diretório do aplicativo, e não do servidor remoto. As solicitações são remapeadas derivem elas de navegação de página ou de um XMLHttpRequest. Para evitar bloquear solicitações de dados acidentalmente para o seu servidor remoto, mapeie sandboxRoot para um subdiretório da URL remota, e não da raiz. O diretório não precisa existir. Por exemplo, para permitir solicitações ao www.example.com para ser carregado do servidor remoto, e não do diretório do aplicativo, altere o iframe anterior para o seguinte: <iframe id="mashup" src="http://www.example.com/map.html" documentRoot="app:/sandbox/" sandboxRoot="http://www.example.com/air/" allowCrossDomainXHR="true" </iframe> Nesse caso, apenas conteúdo no subdiretório air é carregado localmente. Para obter mais informações sobre o mapeamento de caixa de proteção, consulte “Elementos HTML frame e iframe” na página 227 e “segurança HTML” na página 30. O objeto Canvas O objeto Canvas define uma API para desenhar formas geométricas como linhas, arcos, elipses e polígonos. Para usar a API canvas, você adiciona primeiro um elemento canvas ao documento e, em seguida, desenha nele usando a API Canvas de JavaScript. Na maior parte dos outros aspectos, o objeto Canvas se comporta como uma imagem. O exemplo a seguir desenha um triângulo usando um objeto Canvas: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 223 Sobre o ambiente HTML <html> <body> <canvas id="triangleCanvas" style="width:40px; height:40px;"></canvas> <script> var canvas = document.getElementById("triangleCanvas"); var context = canvas.getContext("2d"); context.lineWidth = 3; context.strokeStyle = "#457232"; context.beginPath(); context.moveTo(5,5); context.lineTo(35,5); context.lineTo(20,35); context.lineTo(5,5); context.lineTo(6,5); context.stroke(); </script> </body> </html> Para obter mais documentação sobre a API Canvas, consulte a Referência em JavaScript do Safari da Apple. Observe que o projeto do Webkit começou recentemente alterando a API Canvas para ser padronizada no HTML 5 Working Draft proposto pela WHATWG (Web Hypertext Application Technology Working Group) e pela W3C. Como resultado, uma parte da documentação na Referência em JavaScript do Safari pode estar inconsistente com a versão de canvas presente no AIR. Cookies Em aplicativos do AIR, apenas o conteúdo em caixas de proteção remotas (conteúdo carregado de fontes http: e https:) pode usar cookies (a propriedade document.cookie). Na caixa de proteção do aplicativo, as APIs do AIR fornecem outro meio para armazenar dados persistentes (como classes EncryptedLocalStore e FileStream). O objeto Clipboard A API Clipboard do WebKit é conduzida com os seguintes eventos: copy, cut e paste. O objeto event transmitido nesses eventos fornece acesso à área de transferência pela propriedade clipboardData. Use os seguintes métodos do objeto clipboardData para ler ou escrever dados da área de transferência: Método Descrição clearData(mimeType) Limpa os dados da área de transferência. Defina o parâmetro mimeType para o tipo MIME dos dados a apagar. getData(mimeType) Obtém os dados da área de transferência. Esse método pode ser chamado apenas em um manipulador para o evento paste. Defina o parâmetro mimeType para o tipo MIME dos dados a retornar. setData(mimeType, data) Copia dados para a área de transferência. Defina o parâmetro mimeType para o tipo MIME dos dados. O código JavaScript fora da caixa de proteção do aplicativo pode acessar apenas a área de transferência por esses eventos. No entanto, o conteúdo na caixa de proteção do aplicativo pode acessar a área de transferência do sistema diretamente usando a classe Clipboard do AIR. Por exemplo, você poderia usar a seguinte instrução para obter dados do formato do texto na área de transferência: var clipping = air.Clipboard.generalClipboard.getData("text/plain", air.ClipboardTransferMode.ORIGINAL_ONLY); Os tipos MIME de dados válidos são: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 224 Sobre o ambiente HTML Tipo MIME Valor Texto "text/plain" HTML "text/html" URL "text/uri-list" Bitmap "image/x-vnd.adobe.air.bitmap" Lista de arquivos "application/x-vnd.adobe.air.file-list" Importante: Apenas conteúdo na caixa de proteção do aplicativo pode acessar dados de arquivos presentes na área de transferência. Se um conteúdo que não seja de aplicativo tentar acessar um objeto de arquivo da área de transferência, será lançado um erro de segurança. Para obter mais informações sobre o uso da área de transferência, consulte “Copiar e colar” na página 149 e Utilização da área de trabalho de JavaScript (Centro de desenvolvedores da Apple). Arrastar e soltar Gestos de arrastar e soltar para dentro e para fora do HTML produzem os seguintes eventos DOM: dragstart, drag, dragend, dragenter, dragover, dragleave e drop. O objeto event transmitido nesses eventos fornece acesso aos dados arrastados pela propriedade dataTransfer. A propriedade dataTransfer faz referência a um objeto que fornece os mesmos métodos do objeto clipboardData associado a um evento clipboard. Por exemplo, você poderia usar a seguinte função para obter dados do formato de um evento drop: function onDrop(dragEvent){ return dragEvent.dataTransfer.getData("text/plain", air.ClipboardTransferMode.ORIGINAL_ONLY); } O objeto dataTransfer possui os seguintes membros importantes: Membro Descrição clearData(mimeType) Limpa os dados. Defina o parâmetro mimeType para o tipo MIME da representação de dados para apagar. getData(mimeType) Obtém os dados arrastados. Esse método pode ser chamado apenas em um manipulador para o evento drop. Defina o parâmetro mimeType para o tipo MIME dos dados a obter. setData(mimeType, data) Defina os dados a serem arrastados. Defina o parâmetro mimeType para o tipo MIME dos dados. tipos Uma matriz de seqüências de caracteres contendo os tipos MIME de todas as representações de dados disponíveis no momento no objeto dataTransfer. effectsAllowed Especifica se os dados que estão sendo arrastados podem ser copiados, movidos, vinculados ou alguma combinação disso. Defina a propriedade effectsAllowed no manipulador para o evento dragstart. dropEffect Especifica quais dos efeitos drop permitidos são suportados por um drag target. Defina a propriedade dropEffect no manipulador para o evento dragEnter. Durante a ação de arrastar, o cursor muda para indicar que efeito ocorreria se o usuário soltasse o mouse. Se nenhum dropEffect for especificado, um efeito da propriedade effectsAllowed será escolhido. O efeito de copiar tem prioridade sobre o efeito de mover, que por si só tem prioridade sobre o efeito de vincular. O usuário pode modificar a prioridade padrão usando o teclado. Para obter mais informações sobre como adicionar suporte para arrastar e soltar em um aplicativo do AIR, consulte “Arrastar e soltar” na página 133 e Utilização de arrastar e soltar de JavaScript (Centro de desenvolvedores da Apple). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 225 Sobre o ambiente HTML Propriedades innerHTML e outerHTML O AIR coloca restrições de segurança sobre o uso das propriedades innerHTML e outerHTML para conteúdo em execução na caixa de proteção do aplicativo. Antes do evento de carregamento da página, bem como durante a execução de qualquer manipulador de evento de carregamento, o uso das propriedades innerHTML e outerHTML é irrestrito. No entanto, depois que a página é carregada, você pode apenas usar as propriedades innerHTML ou outerHTML para adicionar conteúdo estático ao documento. Qualquer instrução na seqüência de caracteres atribuída a innerHTML ou outerHTML avaliada como código executável é ignorada. Por exemplo, se você incluir um atributo de retorno de evento em uma definição de elemento, o ouvinte de eventos não será adicionado. Da mesma forma, tags <script> incorporadas não são avaliadas. Para obter mais informações, consulte “segurança HTML” na página 30. Métodos Document.write() e Document.writeln() O uso dos métodos write() e writeln() não é restrito à caixa de proteção do aplicativo antes do evento load da página. No entanto, depois que a página é carregada, chamar um desses métodos não limpa a página ou cria uma nova. Em uma caixa de proteção que não seja de aplicativo, como na maioria dos navegadores da Web, chamar document.write() ou writeln(), após a conclusão do carregamento de uma página, limpa a página atual e abre uma nova em branco. Propriedade Document.designMode Defina a propriedade document.designMode para um valor de on para tornar todos os elementos do documento editáveis. O suporte a editor incorporado inclui editar texto, copiar, colar e arrastar e soltar. Definir designMode como on é equivalente a definir a propriedade contentEditable do elemento body como true. Você pode usar a propriedade contentEditable na maioria dos elementos HTML para definir que seções de um documento são editáveis. Consulte “Atributo contentEditable HTML” na página 230 para obter informações adicionais. Eventos unload (para objetos body e frameset) Na tag de nível superior frameset ou body de uma janela (incluindo a janela principal do aplicativo), não use o evento unload para responder à janela (ou aplicativo) que está sendo fechada. Em vez disso, use o evento exiting do objeto NativeApplication (para detectar quando um aplicativo está sendo fechando). Em vez disso, use o evento exiting do objeto NativeWindow (para detectar quando um aplicativo está sendo fechado). Por exemplo, o seguinte código JavaScript exibe uma mensagem ("Goodbye.") quando o usuário fecha o aplicativo: var app = air.NativeApplication.nativeApplication; app.addEventListener(air.Event.EXITING, closeHandler); function closeHandler(event) { alert("Goodbye."); } No entanto, scripts podem responder com êxito ao evento unload causado pela navegação de um conteúdo frame, iframe ou window de nível superior. Nota: Essas limitações podem ser removidas em uma versão futura do Adobe AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 226 Sobre o ambiente HTML Objeto Window do JavaScript O objeto Window permanece o objeto global no contexto de execução do JavaScript. Na caixa de proteção do aplicativo, o AIR adiciona novas propriedades ao objeto Window do JavaScript para fornecer acesso às classes incorporadas do AIR, bem como importantes objetos de host. Além disso, alguns métodos e propriedades se comportam de modo diferente dependendo se estão ou não na caixa de proteção do aplicativo. Propriedade Window.runtime A propriedade runtime permite que você instancie e use classes runtime incorporadas da caixa de proteção do aplicativo. Essas classes incluem APIs do AIR e do Flash Player (mas não, por exemplo, a estrutura do Flex). Por exemplo, a seguinte instrução cria um objeto de arquivo do AIR: var preferencesFile = new window.runtime.flash.filesystem.File(); O arquivo AIRAliases.js, fornecido no SDK do AIR, contém definições de aliases que permitem a você encurtar tais referências. Por exemplo, quando AIRAliases.js é importado em uma página, um objeto File pode ser criado com a seguinte instrução: var preferencesFile = new air.File(); A propriedade window.runtime somente é definida para conteúdo dentro da caixa de proteção do aplicativo e apenas para o documento pai de uma página com frames ou iframes. Consulte “Uso do arquivo AIRAliases.js” na página 239. Propriedade Window.nativeWindow A propriedade nativeWindow fornece uma referência ao objeto de janela nativa subjacente. Com essa propriedade, você pode fazer o script de funções e propriedades de janela, como posição da tela, tamanho e visibilidade e manipular eventos de janela, como fechar, redimensionar e mover. Por exemplo, a seguinte instrução fecha a janela: window.nativeWindow.close(); Nota: Os recursos de controle da janela fornecidos pelo objeto NativeWindow sobrepõem os recursos fornecidos pelo objeto Window do JavaScript. Em tais casos, você pode usar qualquer método que considerar mais conveniente. A propriedade window.nativeWindow somente é definida para conteúdo dentro da caixa de proteção do aplicativo e apenas para o documento pai de uma página com frames ou iframes. Propriedade Window.htmlLoader A propriedade htmlLoader fornece uma referência ao objeto AIR HTMLLoader que contém o conteúdo HTML. Com essa propriedade, você pode fazer o script da aparência e do comportamento do ambiente HTML. Por exemplo, você pode usar a propriedade htmlLoader.paintsDefaultBackground para determinar se o controle pinta um plano de fundo branco padrão: window.htmlLoader.paintsDefaultBackground = false; Nota: O objeto HTMLLoader por si só possui uma propriedade window, que faz referência ao objeto Window do JavaScript do conteúdo HTML contido nele. Você pode usar essa propriedade para acessar o ambiente JavaScript por uma referência ao HTMLLoader contido. A propriedade window.htmlLoader somente é definida para conteúdo dentro da caixa de proteção do aplicativo e apenas para o documento pai de uma página com frames ou iframes. Propriedades Window.parentSandboxBridge e Window.childSandboxBridge As propriedades parentSandboxBridge e childSandboxBridge permitem que você defina uma interface entre um frame filho e um pai. Para obter mais informações, consulte “Conteúdo entre scripts em caixas de proteção de segurança distintas” na página 248. Funções Window.setTimeout() e Window.setInterval() O AIR coloca restrições de segurança sobre o uso das funções setTimeout() e setInterval() na caixa de proteção do aplicativo. Não é possível definir o código a ser executado como uma seqüência de caracteres ao chamar setTimeout() ou setInterval(). É necessário usar uma referência de função. Para obter mais informações, consulte “setTimeout() e setInterval()” na página 237. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 227 Sobre o ambiente HTML Função Window.open() Quando chamado por código em execução em uma caixa de proteção que não seja de aplicativo, o método open() abrirá somente uma janela quando chamado como resultado da interação do usuário (como um clique do mouse ou pressionamento de tecla). Além disso, o título da janela é prefixado com o título do aplicativo (para impedir que janelas sejam abertas por conteúdo remoto personifiquem janelas abertas pelo aplicativo). Para obter mais informações, consulte o capítulo “Restrições na chamada do método window.open() de JavaScript” na página 35. Objeto air.NativeApplication O objeto NativeApplication fornece informações sobre o estado do aplicativo, despacha vários eventos de nível de aplicativo importantes e fornece funções úteis para controlar o comportamento do aplicativo. Uma única instância do objeto NativeApplication é criada automaticamente e pode ser acessada pela propriedade NativeApplication.nativeApplication definida pela classe. Para acessar o objeto do código JavaScript, você poderia usar: var app = window.runtime.flash.desktop.NativeApplication.nativeApplication; Ou, se o script AIRAliases.js tiver sido importado, você poderia usar a forma mais curta: var app = air.NativeApplication.nativeApplication; O objeto NativeApplication pode apenas ser acessado de dentro da caixa de proteção do aplicativo. A interação com o sistema operacional “Trabalho com tempo de execução e informações do sistema operacional” na página 299 descreve o objeto NativeApplication em detalhes. O esquema de URL JavaScript A execução do código definida em um esquema de URL de JavaScript (como em href="javascript:alert('Test')") é bloqueada na caixa de proteção do aplicativo. Nenhum erro é lançado. Extensões para HTML O AIR e o WebKit definem alguns atributos e elementos HTML não-padrão, incluindo: “Elementos HTML frame e iframe” na página 227 “Elemento Canvas HTML” na página 229 “Manipuladores de eventos de elementos HTML” na página 230 Elementos HTML frame e iframe O AIR adiciona novos atributos aos elementos frame e iframe de conteúdo na caixa de proteção do aplicativo: Atributo sandboxRoot O atributo sandboxRoot especifica um domínio de origem alternativo que não seja de aplicativo para o arquivo especificado pelo atributo src do frame. O arquivo é carregado na caixa de proteção que não seja de aplicativo correspondente ao domínio especificado. O conteúdo no arquivo e o conteúdo carregado do domínio especificado podem cruzar scripts entre si. Importante: Se você definir o valor de sandboxRoot para a URL base do domínio, todas as solicitações para conteúdo desse domínio serão carregadas do diretório do aplicativo, e não do servidor remoto (resulte a solicitação de navegação de página, de um XMLHttpRequest ou de qualquer outro meio de carregar conteúdo). Atributo documentRoot O atributo documentRoot especifica o diretório local a partir do qual carregar URLs que procuram endereços para arquivos no local especificado por sandboxRoot. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 228 Sobre o ambiente HTML Ao consultar endereços de URLs, no atributo src do frame ou no conteúdo carregado no frame, a parte da URL que corresponde ao valor especificado em sandboxRoot é substituída pelo valor especificado em documentRoot. Portanto, na seguinte tag de frame: <iframe src="http://www.example.com/air/child.html" documentRoot="app:/sandbox/" sandboxRoot="http://www.example.com/air/"/> child.html é carregado do subdiretório sandbox da pasta de instalação do aplicativo. Os endereços das URLs relativas em child.html são procurados com base no diretório sandbox. Observe que qualquer arquivo no servidor remoto em www.example.com/air não pode ser acessado no frame, uma vez que o AIR tentaria carregá-lo do diretório app:/sandbox/. Atributo allowCrossDomainXHR Inclua allowCrossDomainXHR="allowCrossDomainXHR" na tag de frame de abertura para permitir que o conteúdo no frame faça XMLHttpRequests para qualquer domínio remoto. Por padrão, o conteúdo que não é de aplicativo apenas pode fazer tais solicitações em seu próprio domínio de origem. Existem implicações de segurança sérias envolvidas na permissão de XHRs entre domínios. O código da página pode trocar dados com qualquer domínio. Se o conteúdo mal-intencionado é de certa forma injetado na página, qualquer dado acessível para código na caixa de proteção atual pode ficar comprometido. Apenas ative XHRs entre domínios para páginas que você cria e controla e somente quando o carregamento de dados entre domínios for realmente necessário. Além disso, valide cuidadosamente todos os dados externos carregados pela página para impedir a injeção de dados ou outras formas de ataque. Importante: Se o atributo allowCrossDomainXHR for incluído em um elemento frame ou iframe, XHRs entre domínios serão ativados (a menos que o valor atribuído seja "0" ou comece com as letras "f" ou "n"). Por exemplo, definir allowCrossDomainXHR como "deny" ainda ativaria XHRs entre domínios. Deixe o atributo totalmente fora da declaração do elemento se não desejar ativar solicitações entre domínios. Atributo ondominitialize Especifica um manipulador de eventos para o evento dominitialize de um frame. Esse é um evento específico do AIR disparado quando os objetos window e document do frame tiverem sido criados, mas antes que qualquer script tenha sido analisado ou elementos document tenham sido criados. O frame despacha o evento dominitialize cedo o suficiente na seqüência de carregamento de forma que qualquer script na página filha possa se referir a objetos, variáveis e funções adicionadas ao documento filho pelo manipulador dominitialize. A página pai deve estar na mesma caixa de proteção da filha para adicionar ou acessar diretamente qualquer objeto em um documento filho. No entanto, um pai na caixa de proteção do aplicativo pode estabelecer uma ponte de caixa de proteção para se comunicar com conteúdo em uma caixa de proteção que não seja de aplicativo. Os exemplos a seguir ilustram o uso da tag iframe no AIR: Coloque child.html em uma caixa de proteção remota, sem mapear para um domínio real em um servidor remoto: <iframe src="http://localhost/air/child.html" documentRoot="app:/sandbox/" sandboxRoot="http://localhost/air/"/> Coloque child.html em uma caixa de proteção remota, permitindo XMLHttpRequests apenas para www.example.com: <iframe src="http://www.example.com/air/child.html" documentRoot="app:/sandbox/" sandboxRoot="http://www.example.com/air/"/> Coloque child.html em uma caixa de proteção remota, permitindo XMLHttpRequests para qualquer domínio remoto: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 229 Sobre o ambiente HTML <iframe src="http://www.example.com/air/child.html" documentRoot="app:/sandbox/" sandboxRoot="http://www.example.com/air/" allowCrossDomainXHR="allowCrossDomainXHR"/> Coloque child.html em uma caixa de proteção local com sistema de arquivos: <iframe src="file:///templates/child.html" documentRoot="app:/sandbox/" sandboxRoot="app-storage:/templates/"/> Coloque child.html em uma caixa de proteção remota, usando o evento dominitialize para estabelecer uma ponte de caixa de proteção: <html> <head> <script> var bridgeInterface = {}; bridgeInterface.testProperty = "Bridge engaged"; function engageBridge(){ document.getElementById("sandbox").parentSandboxBridge = bridgeInterface; } </script> </head> <body> <iframe id="sandbox" src="http://www.example.com/air/child.html" documentRoot="app:/" sandboxRoot="http://www.example.com/air/" ondominitialize="engageBridge()"/> </body> </html> O documento child.html a seguir ilustra como o conteúdo filho pode acessar a ponte de caixa de proteção pai: <html> <head> <script> document.write(window.parentSandboxBridge.testProperty); </script> </head> <body></body> </html> Para obter mais informações, consulte “Conteúdo entre scripts em caixas de proteção de segurança distintas” na página 248 e “segurança HTML” na página 30. Elemento Canvas HTML Define uma área de desenho para uso com a API Canvas do Webkit. Comandos gráficos não podem ser especificados na tag em si. Para desenhar na tela, chame os métodos de desenho de tela por JavaScript. <canvas id="drawingAtrium" style="width:300px; height:300px;"></canvas> Para obter mais informações, consulte “O objeto Canvas” na página 222. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 230 Sobre o ambiente HTML Manipuladores de eventos de elementos HTML Objetos DOM no AIR e no Webkit despacham alguns eventos não encontrados no modelo de eventos DOM padrão. A tabela a seguir lista os atributos de eventos relacionados que podem ser usados para especificar manipuladores para estes eventos: Nome do atributo de retorno de chamada Descrição oncontextmenu Chamado quando um menu de contexto é invocado, como pelo clique do botão direito do mouse ou clique da tecla Command no texto selecionado. oncopy Chamado quando uma seleção em um elemento é copiada. oncut Chamado quando uma seleção em um elemento é cortada. ondominitialize Chamado quando o DOM de um documento carregado em um frame ou iframe é criado, mas antes que qualquer elemento de DOM seja criado ou script analisado. ondrag Chamado quando um elemento é arrastado. ondragend Chamado quando uma ação de arrastar é liberada. ondragenter Chamado quando um gesto de ação de arrastar entra nos limites de um elemento. ondragleave Chamado quando um gesto de ação de arrastar deixa os limites de um elemento. ondragover Chamado continuamente enquanto um gesto de ação de arrastar está dentro dos limites de um elemento. ondragstart Chamado quando um gesto de ação de arrastar é iniciado. ondrop Chamado quando um gesto de ação de arrastar é liberado sobre um elemento. onerror Chamado quando um erro ocorre ao carregar um elemento. oninput Chamado quanto o texto é inserido em um elemento de formulário. onpaste Chamado quando um item é colado em um elemento. onscroll Chamado quando o conteúdo de um elemento rolável é rolado. onsearch Chamado quando um elemento é copiado (? docs da Apple corretos ?) onselectstart Chamado quando uma seleção é iniciada. Atributo contentEditable HTML Você pode adicionar o atributo contentEditable a qualquer elemento HTML para permitir aos usuários editar o conteúdo do elemento. Por exemplo, o seguinte código de exemplo HTML define todo o documento como editável, exceto para o primeiro elemento p: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 231 Sobre o ambiente HTML <html> <head/> <body contentEditable="true"> <h1>de Finibus Bonorum et Malorum</h1> <p contentEditable="false">Sed ut perspiciatis unde omnis iste natus error.</p> <p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis.</p> </body> </html> Nota: Se você define a propriedade document.designMode como on, todos os elementos do documento são editáveis, independentemente da configuração de contentEditable para um elemento individual. No entanto, definir designMode como off não desativa a edição de elementos para os quais contentEditable é true. Consulte “Propriedade Document.designMode” na página 225 para obter informações adicionais. Extensões para o CSS O WebKit suporta várias propriedades CSS estendidas. A tabela a seguir lista as propriedades estendidas para as quais o suporte é estabelecido. As propriedades adicionais não-padrão estão disponíveis no WebKit, mas não são totalmente suportadas no AIR, porque ainda estão em desenvolvimento no WebKit ou porque são recursos experimentais que podem ser removidos no futuro. Nome de propriedade CSS Valores Descrição -webkit-border-horizontal-spacing Unidade de comprimento não-negativa Especifica o componente horizontal do espaçamento da borda. -webkit-border-vertical-spacing Unidade de comprimento não-negativa Especifica o componente vertical do espaçamento da borda. -webkit-line-break after-white-space, normal Especifica a regra de quebra de linha a ser usada para texto em chinês, japonês e coreano (CJK). -webkit-margin-bottom-collapse collapse, discard, separate Define como a margem inferior de uma célula de tabela é recolhida. -webkit-margin-collapse collapse, discard, separate Define como as margem superior e inferior de uma célula de tabela é recolhida. -webkit-margin-start Qualquer unidade de comprimento. A largura da margem inicial. Para texto da esquerda para a direita, essa propriedade substitui a margem esquerda. Para texto da direita para a esquerda, essa propriedade substitui a margem direita. -webkit-margin-top-collapse collapse, discard, separate Define como a margem superior de uma célula de tabela é recolhida. -webkit-nbsp-mode normal, space Define o comportamento de espaços nãoseparáveis no conteúdo delimitado. -webkit-padding-start Qualquer unidade de comprimento. Especifica a largura do preenchimento inicial. Para texto da esquerda para a direita, essa propriedade substitui o valor do preenchimento esquerdo. Para texto da direita para a esquerda, essa propriedade substitui o valor do preenchimento direito. -webkit-rtl-ordering logical, visual Substitui a manipulação padrão de texto mesclado da esquerda para a direita e da direita para a esquerda. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 232 Sobre o ambiente HTML Nome de propriedade CSS Valores Descrição -webkit-text-fill-color Qualquer cor nomeada ou valor de cor numérico Especifica a cor de preenchimento do texto. -webkit-text-security circle, disc, none, square Especifica a forma de substituição a ser usada em um campo de entrada de senha. -webkit-user-drag • auto — Comportamento padrão Substitui o comportamento de ação de arrastar automático. • element — Todo o elemento é arrastado • none — O elemento não pode ser arrastado -webkit-user-modify read-only, read-write, read-writeplaintext-only Especifica se o conteúdo de um elemento pode ser editado. -webkit-user-select • auto — Comportamento padrão Especifica se um usuário pode selecionar o conteúdo de um elemento. • none — O elemento não pode ser selecionado • text — É possível selecionar apenas texto no elemento Para obter mais informações, consulte a Referência do CSS do Apple Safari (http://developer.apple.com/documentation/AppleApplications/Reference/SafariCSSRef/). 233 Capítulo 21: Programação em HTML e JavaScript Vários tópicos de programação são exclusivos para o desenvolvimento de aplicativos Adobe® AIR™ com HTML e JavaScript. As seguintes informações são importantes caso você esteja programando um aplicativo baseado em HTML ou um aplicativo AIR baseado em SWF que execute HTML e JavaScript usando a classe HTMLLoader (ou o componente mx:HTML Flex™). Sobre a classe HTMLLoader A classe HTMLLoader do Adobe AIR define o objeto de exibição que pode exibir conteúdo HTML em um aplicativo AIR. Os aplicativos baseados em SWF podem adicionar um controle HTMLLoader a uma janela existente ou criar uma janela HTML que contenha automaticamente um objeto HTMLLoader com HTMLLoader.createRootWindow(). O objeto HTMLLoader pode ser acessado por meio da propriedade window.htmlLoader de JavaScript de dentro da página HTML carregada. Carregamento de conteúdo HTML de uma URL O código a seguir carrega uma URL no objeto HTMLLoader (adicione o HTMLLoader como filho do estágio ou outro contêiner do objeto de exibição para exibir o conteúdo HTML no seu aplicativo): import flash.html.HTMLLoader; var html:HTMLLoader = new HTMLLoader; html.width = 400; html.height = 600; var urlReq:URLRequest = new URLRequest("http://www.adobe.com/"); html.load(urlReq); Por padrão, as propriedades width e height de um objeto HTMLLoader são definidas como 0. Você desejará definir essas dimensões quando adicionar um objeto HTMLLoader ao palco. O HTMLLoader despacha diversos eventos à medida que a página carrega. Você pode usar esses eventos para determinar quando é seguro interagir com a página carregada. Esses eventos são descritos em “Tratamento de eventos relacionados a HTML” na página 252. Você também pode processar texto HTML usando a classe TextField, mas os respectivos recursos são limitados. A classe Textfield do Adobe® Flash® Player oferece suporte a um subconjunto de markup de HTML, mas, devido a limitações de tamanho, os recursos respectivos são limitados. (A classe HTMLLoader incluída no Adobe AIR não está disponível no Flash Player.) Carregamento de conteúdo HTML de uma string O método loadString() do objeto HTMLLoader carrega uma string de conteúdo HTML no objeto HTMLLoader: var html:HTMLLoader = new HTMLLoader(); var htmlStr:String = "<html><body>Hello <b>world</b>.</body></html>"; html.loadString(htmlStr); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 234 Programação em HTML e JavaScript Por padrão, o conteúdo carregado por meio do método loadString() é colocado em uma caixa de proteção que não é aplicativo com as seguintes características: • Ela tem acesso ao conteúdo carregado da rede (mas não do sistema de arquivos). • Ela não pode carregar dados usando XMLHttpRequest. • A propriedade window.location é definida como "about:blank". • O conteúdo não pode acessar a propriedade window.runtime (como pode em qualquer caixa de proteção que não é aplicativo). No AIR 1.5, a classe HTMLLoader inclui uma propriedade placeLoadStringContentInApplicationSandbox. Quando essa propriedade é definida como true para um objeto HTMLLoader, o conteúdo carregado pelo método loadString() é colocado na caixa de proteção do aplicativo. (O valor padrão é false.) Isso fornece ao conteúdo carregado pelo método loadString() acesso à propriedade window.runtime e a todas as APIs do ARI. Se você definir essa propriedade como true, assegure que a fonte de dados para uma seqüência de caracteres usada em uma chamada para o método loadString() seja confiável. As instruções de código na seqüência de caracteres HTML são executadas com privilégios totais de aplicativo quando essa propriedade é definida como true. Só defina a propriedade como true quando estiver certo de que a seqüência de caracteres não possa conter código nocivo. Em aplicativos compilados com SDKs do AIR 1.0 ou 1.1, o conteúdo carregado pelo método loadString() é inserido na caixa de proteção do aplicativo. Regras de segurança importantes no uso de HTML em aplicativos AIR Os arquivos instalados com o aplicativo AIR têm acesso às respectivas APIs. Por motivos de segurança, o conteúdo de outras fontes não tem acesso. Por exemplo, essa restrição impede que conteúdo de um domínio remoto (como http://example.com) leia o conteúdo de diretório da área de trabalho do usuário (ou algo pior). Como há buracos de segurança que podem ser explorados através da chamada da função eval() (e APIs relacionadas), o conteúdo instalado com o aplicativo, por padrão, não pode usar esses métodos. No entanto, algumas estruturas Ajax usam a chamada da função eval() e APIs relacionadas. Para estruturar adequadamente o conteúdo para trabalhar em um aplicativo AIR, você deve considerar as regras das restrições de segurança sobre conteúdo de fontes diversas. O conteúdo de fontes diversas é colocado em classificações de segurança distintas, chamadas de caixas de proteção (consulte “Caixas de proteção” na página 27). Por padrão, o conteúdo instalado com o aplicativo está instalado em uma caixa de proteção conhecida como caixa de proteção de aplicativo e isso concede a ele acesso às APIs do AIR. Normalmente, a caixa de proteção do aplicativo é a mais segura, com restrições projetadas para impedir a execução de código não confiável. O tempo de execução permite carregar o conteúdo instalado com o aplicativo em uma caixa de proteção diferente da caixa de proteção do aplicativo. O conteúdo em caixas de proteção não-aplicativo opera em um ambiente de segurança semelhante ao de um navegador da Web típico. Por exemplo, o código das caixas de proteção não-aplicativos pode usar eval() e métodos relacionados (mas, ao mesmo tempo, não é permitido acesso às APIs do AIR). O tempo de execução inclui maneiras de fazer com que o conteúdo em caixas de proteção distintas se comuniquem com segurança (sem expor, por exemplo, as APIs do AIR a conteúdo de não-aplicativo). Para obter detalhes, consulte “Conteúdo entre scripts em caixas de proteção de segurança distintas” na página 248. Se você chamar um código com uso restrito em uma caixa de proteção por motivos de segurança, o tempo de execução despachará um erro JavaScript: "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo." Para evitar esse erro, siga as práticas de codificação descritas na próxima seção, “Como evitar erros JavaScript relacionados à segurança” na página 235. Para obter mais informações, consulte “segurança HTML” na página 30. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 235 Programação em HTML e JavaScript Como evitar erros JavaScript relacionados à segurança Se você chamar um código com uso restrito em uma caixa de proteção, devido a essas restrições de segurança, o tempo de execução despachará um erro de JavaScript: "Violação de segurança de tempo de execução do Adobe AIR para código JavaScript na caixa de proteção de segurança do aplicativo." Para evitar esse erro, siga essas práticas de codificação. Causas de erros JavaScript relacionados à segurança O código em execução na caixa de proteção do aplicativo está restrito à maioria das operações que envolvem avaliação e execução de seqüências depois que o evento load tiver sido disparado e todos os manipuladores de evento load tiverem encerrado. A tentativa de usar os seguintes tipos de instruções JavaScript que avaliam e executam strings potencialmente inseguras gera erros JavaScript: • função eval() • setTimeout() e setInterval() • Construtor de funções Além disso, os tipos de instruções JavaScript seguintes falham sem gerar um erro JavaScript inseguro: • javascript: URLs • Retornos de chamada de evento atribuídos por meio de atributos onevent em instruções innerHTML e outerHTML • Carregamento de arquivos JavaScript externos ao diretório de instalação do aplicativo • document.write() e document.writeln() • XMLHttpRequests síncronas antes do evento load ou durante um manipulador de eventos load • Elementos de script criados dinamicamente Nota: Em alguns casos restritos, a avaliação de strings é permitida. Consulte “Restrições de código de conteúdo em caixas de proteção distintas” na página 32 para obter mais informações. A Adobe mantém uma lista das estruturas Ajax conhecidas para oferecer suporte à caixa de proteção de segurança do aplicativo em http://www.adobe.com/go/airappsandboxframeworks_br. As seções seguintes descrevem como regravar os scripts para evitar esses erros JavaScript inseguro e falhas silenciosas do código em execução na caixa de proteção do aplicativo. Mapeamento de conteúdo do aplicativo para uma caixa de proteção distinta Na maioria dos casos, você pode regravar ou reestruturar o aplicativo para evitar erros JavaScript relacionados à segurança. No entanto, quando não for possível regra ou reestruturar, você poderá carregar o conteúdo do aplicativo em uma caixa de proteção distinta usando a técnica descrita em “Carregamento de conteúdo do aplicativo em uma caixa de proteção "não aplicativo"” na página 248. Se esse conteúdo também deve acessar as APIs do AIR, você pode criar uma ponte de caixa de proteção, conforme descrito em “Configuração de interface de ponte de caixa de proteção” na página 249. função eval() Na caixa de proteção do aplicativo, a função eval() só pode ser usada antes do evento load da página ou durante o manipulador de eventos load. Após a página ter sido carregada, as chamadas para eval() não executarão código. No entanto, nos seguintes casos, você pode regravar o código para evitar o uso de eval(). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 236 Programação em HTML e JavaScript Atribuição de propriedades a um objeto Em vez de analisar uma string para criar o acessador de propriedades: eval("obj." + propName + " = " + val); acesse propriedades com notação entre colchetes: obj[propName] = val; Criação de função com variáveis disponíveis no contexto Substitua instruções como as seguintes: function compile(var1, var2){ eval("var fn = function(){ this."+var1+"(var2) }"); return fn; } com: function compile(var1, var2){ var self = this; return function(){ self[var1](var2) }; } Criação de objeto usando o nome da classe como parâmetro de seqüência Considere uma classe JavaScript hipotética definida com o seguinte código: var CustomClass = { Utils: { Parser: function(){ alert('constructor') } }, Data: { } }; var constructorClassName = "CustomClass.Utils.Parser"; A maneira mais simples de criar uma ocorrência é usar eval(): var myObj; eval('myObj=new ' + constructorClassName +'()') No entanto, você pode evitar a chamada para eval(), analisando cada componente de nome de classe e criando o novo objeto usando notação entre colchetes: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 237 Programação em HTML e JavaScript function getter(str) { var obj = window; var names = str.split('.'); for(var i=0;i<names.length;i++){ if(typeof obj[names[i]]=='undefined'){ var undefstring = names[0]; for(var j=1;j<=i;j++) undefstring+="."+names[j]; throw new Error(undefstring+" is undefined"); } obj = obj[names[i]]; } return obj; } Para criar a ocorrência, use: try{ var Parser = getter(constructorClassName); var a = new Parser(); }catch(e){ alert(e); } setTimeout() e setInterval() Substitua a string passada como a função do manipulador por uma referência de função ou objeto. Por exemplo, substitua uma instrução como a seguinte: setTimeout("alert('Timeout')", 10); com: setTimeout(alert('Timeout'), 10); Ou, quando a função precisar que o objeto this seja definido pelo chamador, substitua uma instrução como: this.appTimer = setInterval("obj.customFunction();", 100); pelo seguinte: var _self = this; this.appTimer = setInterval(function(){obj.customFunction.apply(_self);}, 100); Construtor de funções As chamadas para new Function(param, body) podem ser substituídas por uma declaração de função inline ou usadas apenas antes que o evento load da página tenha sido tratado. javascript: URLs O código definido em um link usando o javascript: O esquema de URL é ignorado na caixa de proteção do aplicativo. Não é gerado nenhum erro JavaScript inseguro. Você pode substituir links usando javascript: URLs, como: <a href="javascript:code()">Click Me</a> com: <a href="#" onclick="code()">Click Me</a> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 238 Programação em HTML e JavaScript Retornos de chamada de evento atribuídos por meio de atributos onevent em instruções innerHTML e outerHTML Ao usar innerHTML ou outerHTML para adicionar elementos ao DOM de um documento, todos os retornos de chamadas de evento atribuídos na instrução, como onclick ou onmouseover, são ignorados. Nenhum erro de segurança é gerado. Em vez disso, você pode atribuir um atributo id aos novos elementos e definir as funções de retorno de chamada do manipulador de eventos, usando o método addEventListener(). Por exemplo, determinado um elemento de destino em um documento, como: <div id="container"></div> Substitua instruções como: document.getElementById('container').innerHTML = '<a href="#" onclick="code()">Click Me.</a>'; com: document.getElementById('container').innerHTML = '<a href="#" id="smith">Click Me.</a>'; document.getElementById('smith').addEventListener("click", function() { code(); }); Carregamento de arquivos JavaScript externos ao diretório de instalação do aplicativo Não é permitido o carregamento de arquivos de script externos à caixa de proteção do aplicativo. Nenhum erro de segurança é gerado. Todos os arquivos de script que são executados na caixa de proteção do aplicativo devem ser instalados no diretório do aplicativo. Para usar scripts externos em uma página, você deve mapear a página para uma caixa de proteção distinta. Consulte “Carregamento de conteúdo do aplicativo em uma caixa de proteção "não aplicativo"” na página 248. document.write() e document.writeln() As chamadas para document.write() ou document.writeln() serão ignoradas após o evento load da página ser tratado. Nenhum erro de segurança é gerado. Como alternativa, você pode carregar um novo arquivo ou substituir o corpo do documento usando técnicas de manipulação DOM. XMLHttpRequests síncronas antes do evento load ou durante um manipulador de eventos load As XMLHttpRequests síncronas iniciadas antes do evento load da página ou durante um manipulador de eventos load não retornam nenhum conteúdo. As XMLHttpRequests assíncronas podem ser iniciadas, mas não retornam até depois do evento load. Após o evento load ser tratado, as XMLHttpRequests síncronas se comportam normalmente. Elementos de script criados dinamicamente Elementos de script criados dinamicamente, como quando criados com o innerHTML ou o método document.createElement(), são ignorados. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 239 Programação em HTML e JavaScript Acesso às classes API do AIR no JavaScript Além dos elementos padrão e estendidos de kit da Web, o código HTML e JavaScript pode acessar as classes host fornecidas pelo tempo de execução. Essas classes permitem acessar os recursos avançados que o AIR oferece, incluindo: • Acesso ao sistema de arquivos • Uso de bancos de dados SQL locais • Controle de menus de janela e aplicativo • Acesso a soquetes de rede • Uso de classes e objetos definidos pelo usuário • Recursos de som Por exemplo, a API de arquivo do AIR inclui uma classe File, contida no pacote flash.filesystem. Você pode criar um objeto File em JavaScript da seguinte forma: var myFile = new window.runtime.flash.filesystem.File(); O objeto runtime é um objeto JavaScript especial, disponível para conteúdo HTML em execução no AIR na caixa de proteção do aplicativo. Ele permite acessar as classes de tempo de execução do JavaScript. A propriedade flash do objeto runtime oferece acesso ao pacote flash. Por sua vez, a propriedade flash.filesystem do objeto runtime oferece acesso ao pacote flash.filesystem (e esse pacote inclui a classe File). Os pacotes são uma maneira de organizar as classes usadas no ActionScript. Nota: A propriedade runtime não é adicionada automaticamente aos objetos window de páginas carregadas em um frame ou iframe. No entanto, desde que o documento filho esteja na caixa de proteção do aplicativo, o filho poderá acessar a propriedade runtime do pai. Como a estrutura de pacote das classes de tempo de execução exigem que os desenvolvedores digitem longas seqüências de código JavaScript para acessar cada classe (como em window.runtime.flash.desktop.NativeApplication), o AIR SDK inclui o arquivo AIRAliases.js, que permite acessar as classes de tempo de execução mais facilmente (por exemplo, digitando simplesmente air.NativeApplication). As classes API do AIR são discutidas em todo este guia. Outras classes da API do Flash Player, que possam ser de interesse dos desenvolvedores HTML, são descritas na Referência da Linguagem do Adobe AIR para Desenvolvedores de HTML. ActionScript é a linguagem usada em conteúdo SWF (Flash Player). No entanto, as sintaxes JavaScript e ActionScript são semelhantes. (ambas se baseiam nas versões da linguagem ECMAScript.) Todas as classes incorporadas estão disponíveis em JavaScript (em conteúdo HTML) e ActionScript (em conteúdo SWF). Nota: O código JavaScript não pode usar as classes Dictionary, XML e XMLList, que estão disponíveis no ActionScript. Uso do arquivo AIRAliases.js As classes de tempo de execução são organizadas em uma estrutura de pacote, da seguinte forma: • window.runtime.flash.desktop.NativeApplication • window.runtime.flash.desktop.ClipboardManager • window.runtime.flash.filesystem.FileStream DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 240 Programação em HTML e JavaScript • window.runtime.flash.data.SQLDatabase No AIR SDK está incluído o arquivo AIRAliases.js que oferece definições de "alias" que permitem acessar as classes de tempo de execução com menos digitação. Por exemplo, você pode acessar as classes listadas acima, bastando, para isso, digitar o seguinte: • air.NativeApplication • air.Clipboard • air.FileStream • air.SQLDatabase A lista é apenas um pequeno subconjunto das classes no arquivo AIRAliases.js. A lista completa de classes e funções em nível de pacote é fornecida na Referência da Linguagem do Adobe AIR para Desenvolvedores de HTML. Além das classes de tempo de execução usadas normalmente, o arquivo AIRAliases.js inclui alias para as funções em nível do pacote usadas com mais freqüência. window.runtime.trace(), window.runtime.flash.net.navigateToURL() e window.runtime.flash.net.sendToURL(), com alias air.trace(), air.navigateToURL() e air.sendToURL(). Para usar o arquivo AIRAliases.js, inclua a seguinte referência de script em sua página HTML: <script src="AIRAliases.js"></script> Ajuste o caminho na referência src, conforme necessário. Importante: Exceto quando observado, o código de exemplo JavaScript nesta documentação pressupõe que você incluiu o arquivo AIRAliases.js em sua página HTML. Sobre URLs no AIR No conteúdo HTML em execução no AIR, você pode usar qualquer um dos seguintes esquemas de URL na definição de atributos src para img, frame, iframe e tags de script, no atributo href de uma tag link ou qualquer outro local que você possa fornecer uma URL. esquema de URL Descrição Exemplo file Um caminho relativo à raiz do sistema de arquivos. file:///c:/AIR Test/test.txt app Um caminho relativo à raiz do diretório do aplicativo instalado. app:/images app-storage Um caminho relativo ao diretório de armazenamento do aplicativo. Para cada aplicativo instalado, o AIR define um diretório exclusivo de armazenamento do aplicativo, que é um local útil para armazenar dados específicos desse aplicativo. app-storage:/settings/prefs.xml http Uma solicitação HTTP padrão. http://www.adobe.com https Uma solicitação HTTPS padrão. https://secure.example.com Para obter mais informações sobre o uso de esquemas de URL no AIR, consulte “Uso de esquemas de URL do AIR em URLs” na página 306. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 241 Programação em HTML e JavaScript Muitas das APIs do AIR, incluindo as classes File, Loader, URLStream e Sound, usam um objeto URLRequest em vez de uma string contendo a URL. O próprio objeto URLRequest é inicializado com uma string, que pode usar qualquer um dos mesmos esquemas de URL. Por exemplo, a seguinte instrução cria um objeto URLRequest que pode ser usado para solicitar a home page da Adobe: var urlReq = new air.URLRequest("http://www.adobe.com/"); Para obter informações sobre objetos URLRequest, consulte “Solicitações de URL e rede” na página 305. Como tornar objetos ActionScript disponíveis para JavaScript O JavaScript na página HTML carregada pelo objeto HTMLLoader pode chamar as classes, os objetos e as funções definidas no contexto de execução do ActionScript, usando as propriedades window.runtime, window.htmlLoader e window.nativeWindow da página HTML. Você também pode tornar objetos e funções ActionScript disponíveis para código JavaScript, criando referências para eles no contexto de execução do JavaScript. Um exemplo básico de como acessar objetos JavaScript do ActionScript O seguinte exemplo ilustra como adicionar propriedades que fazem referência a objetos ActionScript ao objeto window global de uma página HTML. var html:HTMLLoader = new HTMLLoader(); var foo:String = "Hello from container SWF." function helloFromJS(message:String):void { trace("JavaScript says:", message); } var urlReq:URLRequest = new URLRequest("test.html"); html.addEventListener(Event.COMPLETE, loaded); html.load(urlReq); function loaded(e:Event):void{ html.window.foo = foo; html.window.helloFromJS = helloFromJS; } O conteúdo HTML (no arquivo chamado test.html), carregado no objeto HTMLLoader no exemplo anterior, pode acessar a propriedade foo e o método helloFromJS() definidos no arquivo SWF pai: <html> <script> function alertFoo() { alert(foo); } </script> <body> <button onClick="alertFoo()"> What is foo? </button> <p><button onClick="helloFromJS('Hi.')"> Call helloFromJS() function. </button></p> </body> </html> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 242 Programação em HTML e JavaScript Ao acessar o contexto JavaScript de um documento que está sendo carregado, você pode usar o evento htmlDOMInitialize para criar objetos na seqüência de construção da página, cedo o bastante para que qualquer script definido na página possa acessá-los. Se você aguardar o evento complete, somente scripts da página executados depois do evento load da página poderão acessar os objetos adicionados. Como tornar as definições de classe disponíveis para JavaScript Para disponibilizar as classes ActionScript do aplicativo em JavaScript, você pode atribuir o conteúdo HTML carregado ao domínio de aplicativo que contém as definições de classe. O domínio de aplicativo do contexto de execução do JavaScript pode ser definido com a propriedade runtimeApplicationDomain do objeto HTMLLoader. Para definir o domínio de aplicativo como domínio de aplicativo primário, por exemplo, defina runtimeApplicationDomain como ApplicationDomain.currentDomain, conforme mostra o código a seguir: html.runtimeApplicationDomain = ApplicationDomain.currentDomain; Depois que a propriedade runtimeApplicationDomain for definida, o contexto JavaScript compartilha as definições de classe com o domínio atribuído. Para criar uma ocorrência de classe personalizada em JavaScript, faça referência à definição de classe por meio da propriedade window.runtime e use o operador novo: var customClassObject = new window.runtime.CustomClass(); O conteúdo HTML deve ser de um domínio de segurança compatível. Se o conteúdo HTML for de um domínio de segurança diferente do domínio de aplicativo que você atribuir, em vez disso a página usará um domínio de aplicativo padrão. Por exemplo, se você carregar uma página remota da Internet, não poderá atribuir ApplicationDomain.currentDomain como domínio de aplicativo da página. Remoção de ouvintes de eventos Quando você adiciona ouvintes de eventos JavaScript a objetos fora da página atual, incluindo objetos de tempo de execução, objetos no conteúdo SWF carregado e até objetos JavaScript em execução em outras páginas, deve sempre remover esses ouvintes de eventos quando a página for descarregada. Do contrário, o ouvinte de evento despacha o evento para uma função do manipulador que não existe mais. Se isso acontecer, você verá a seguinte mensagem de erro: "O aplicativo tentou fazer referência a um objeto JavaScript em uma página HTML que não é mais carregada". A remoção de ouvintes de eventos desnecessários também permite que o AIR recupere a memória associada. Para obter mais informações, consulte “Remoção de ouvintes de eventos nas páginas HTML que navegam” na página 256. Acesso a objetos HTML DOM e JavaScript do ActionScript Após o objeto HTMLLoader despachar o evento complete, você poderá acessar todos os objetos no HTML DOM (modelo de objeto de documento) da página. Os objetos acessíveis incluem os elementos de exibição (como os objetos div e p na página), bem como as variáveis e funções JavaScript. O evento complete corresponde ao evento load da página em JavaScript. Antes que complete seja despachado, os elementos DOM, as variáveis e as funções poderão não ter sido analisados nem criados. Se possível, aguarde o evento complete antes de acessar o HTML DOM. Por exemplo, considere a seguinte página HTML: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 243 Programação em HTML e JavaScript <html> <script> foo = 333; function test() { return "OK."; } </script> <body> <p id="p1">Hi.</p> </body> </html> Essa página HTML simples define uma variável JavaScript chamada foo e uma função JavaScript chamada test(). As duas propriedades são propriedades do objeto window global da página. Além disso, o objeto window.document inclui um elemento chamado P (com a ID p1), que você pode acessar usando o método getElementById(). Depois que a página for carregada (quando o objeto HTMLLoader despachar o evento complete), você poderá acessar cada um desses objetos do ActionScript, conforme mostra o seguinte código ActionScript: var html:HTMLLoader = new HTMLLoader(); html.width = 300; html.height = 300; html.addEventListener(Event.COMPLETE, completeHandler); var xhtml:XML = <html> <script> foo = 333; function test() { return "OK."; } </script> <body> <p id="p1">Hi.</p> </body> </html>; html.loadString(xhtml.toString()); function completeHandler(e:Event):void { trace(html.window.foo); // 333 trace(html.window.document.getElementById("p1").innerHTML); // Hi. trace(html.window.test()); // OK. } Para acessar o conteúdo de um elemento HTML, use a propriedade innerHTML. Por exemplo, o código anterior usa html.window.document.getElementById("p1").innerHTML para obter o conteúdo do elemento HTML chamado p1. Você também pode definir propriedades da página HTML do ActionScript. Por exemplo, o seguinte exemplo define o conteúdo do elemento p1 e o valor da variável JavaScript foo na página, usando uma referência ao objeto HTMLLoader que a contém: html.window.document.getElementById("p1").innerHTML = "Goodbye"; html.window.foo = 66; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 244 Programação em HTML e JavaScript Incorporação de conteúdo SWF em HTML Você pode incorporar o conteúdo SWF em um conteúdo HTML do aplicativo AIR da mesma forma que em um navegador. Incorpore o conteúdo SWF usando a tag object, a tag embed ou as duas. Nota: Uma prática comum de desenvolvimento é usar tanto uma tag object quanto uma tag embed para exibir conteúdo SWF em uma página HTML. Essa prática não tem nenhum benefício no AIR. Você pode usar a própria tag object padrão W3C no conteúdo para ser exibido no AIR. Ao mesmo tempo, você pode continuar usando as tags object e embed juntas, se necessário, para conteúdo HTML exibido também no navegador. O seguinte exemplo ilustra o uso da tag object HTML para exibir um arquivo SWF no conteúdo HTML. O arquivo SWF é carregado do diretório do aplicativo, mas você pode usar qualquer um dos esquemas de URL suportados pelo AIR. (O local do qual o arquivo SWF é carregado determina a caixa de proteção de segurança em que o AIR coloca o conteúdo.) <object type="application/x-shockwave-flash" width="100%" height="100%"> <param name="movie" value="app:/SWFFile.swf"></param> </object> Você também pode usar um script para carregar conteúdo dinamicamente. O seguinte exemplo cria um nó object para exibir o arquivo SWF especificado no parâmetro urlString. O exemplo adiciona o nó como filho do elemento de página com a ID especificada pelo parâmetro elementID: <script> function showSWF(urlString, elementID){ var displayContainer = document.getElementById(elementID); displayContainer.appendChild(createSWFObject(urlString,650,650)); } function createSWFObject(urlString, width, height){ var SWFObject = document.createElement("object"); SWFObject.setAttribute("type","application/x-shockwave-flash"); SWFObject.setAttribute("width","100%"); SWFObject.setAttribute("height","100%"); var movieParam = document.createElement("param"); movieParam.setAttribute("name","movie"); movieParam.setAttribute("value",urlString); SWFObject.appendChild(movieParam); return SWFObject; } </script> Uso de bibliotecas do ActionScript em uma página HTML O AIR estende o elemento de script HTML para que a página possa importar classes ActionScript em um arquivo SWF compilado. Por exemplo, para importar uma biblioteca chamada myClasses.swf, localizada no subdiretório lib da pasta raiz do aplicativo, inclua a seguinte tag de script no arquivo HTML: <script src="lib/myClasses.swf" type="application/x-shockwave-flash"></script> Importante: O atributo de tipo deve ser type="application/x-shockwave-flash" para que a biblioteca seja carregada corretamente. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 245 Programação em HTML e JavaScript Se o conteúdo SWF for compilado como Flash Player 10 ou AIR 1.5 SWF, você deverá definir o namespace do descritor do aplicativo como espaço para nome do AIR 1.5. Para obter mais informações, consulte “Definição de propriedades no arquivo do descritor do aplicativo” na página 45. O diretório lib e o arquivo myClasses.swf também deve ser incluído quando o arquivo AIR for empacotado. Acesse as classes importadas por meio da propriedade runtime do objeto da janela JavaScript: var libraryObject = new window.runtime.LibraryClass(); Se as classes no arquivo SWF estiverem organizadas em pacotes, você também deverá incluir o nome do pacote. Por exemplo, se a definição LibraryClass estivesse em um pacote chamado utilities, você deveria criar uma ocorrência da classe com a seguinte instrução: var libraryObject = new window.runtime.utilities.LibraryClass(); Nota: Para compilar uma biblioteca SWF do ActionScript para usar como parte da página HTML no AIR, use o compilador acompc. O utilitário acompc é parte do Flex 3 SDK e está descrito na Documentação do Flex 3 SDK. Acesso aos objetos HTML DOM e JavaScript de um arquivo ActionScript importado Para acessar objetos em uma página HTML do ActionScript em um arquivo SWF importado na página usando a tag <script>, passe uma referência para um objeto JavaScript, como window ou document, em uma função definida no código do ActionScript. Use a referência na função para acessar o objeto JavaScript (ou outros objetos acessíveis por meio da referência passada). Por exemplo, considere a seguinte página HTML: <html> <script src="ASLibrary.swf" type="application/x-shockwave-flash"></script> <script> num = 254; function getStatus() { return "OK."; } function runASFunction(window){ var obj = new runtime.ASClass(); obj.accessDOM(window); } </script> <body onload="runASFunction"> <p id="p1">Body text.</p> </body> </html> Essa página HTML simples tem uma variável JavaScript chamada num e uma função JavaScript chamada getStatus(). As duas propriedades são propriedades do objeto window da página. Além disso, o objeto window.document inclui um elemento chamado P (com a ID p1). A página carrega o arquivo ActionScript, "ASLibrary.swf," que contém a classe ASClass. A ASClass define a função chamada accessDOM() que simplesmente rastreia os valores desses objetos JavaScript. O método accessDOM() considera o objeto de janela JavaScript como um argumento. Ao usar essa referência de janela, ele pode acessar outros objetos na página, incluindo variáveis, funções e elementos DOM, conforme ilustrado na definição a seguir: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 246 Programação em HTML e JavaScript public class ASClass{ public function accessDOM(window:*):void { trace(window.num); // 254 trace(window.document.getElementById("p1").innerHTML); // Body text.. trace(window.getStatus()); // OK. } } Você pode obter e definir propriedades da página HTML de uma classe ActionScript importada. Por exemplo, a seguinte função define o conteúdo do elemento p1 na página e define o valor da variável de JavaScript foo na página: public function modifyDOM(window:*):void { window.document.getElementById("p1").innerHTML = "Bye"; window.foo = 66; Conversão de objetos Date e RegExp As linguagens JavaScript e ActionScript definem as classes Date e RegExp, mas os objetos desses tipos não são convertidos automaticamente entre os dois contextos de execução. Você deve converter os objetos Date e RegExp para o tipo equivalente antes de usá-los para definir parâmetros de propriedades ou funções no contexto de execução alternativo. Por exemplo, o seguinte código ActionScript converte o objeto Date de JavaScript chamado jsDate em um objeto Date do ActionScript: var asDate:Date = new Date(jsDate.getMilliseconds()); Por exemplo, o seguinte código ActionScript converte o objeto RegExp de JavaScript chamado jsRegExp em um objeto RegExp do ActionScript: var flags:String = ""; if (jsRegExp.dotAll) flags += "s"; if (jsRegExp.extended) flags += "x"; if (jsRegExp.global) flags += "g"; if (jsRegExp.ignoreCase) flags += "i"; if (jsRegExp.multiline) flags += "m"; var asRegExp:RegExp = new RegExp(jsRegExp.source, flags); Manipulação de folha de estilos HTML do ActionScript Depois que o objeto HTMLLoader tiver despachado o evento complete, você poderá examinar e manipular estilos CSS na página. Por exemplo, considere o seguinte documento HTML simples: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 247 Programação em HTML e JavaScript <html> <style> .style1A { font-family:Arial; font-size:12px } .style1B { font-family:Arial; font-size:24px } </style> <style> .style2 { font-family:Arial; font-size:12px } </style> <body> <p class="style1A"> Style 1A </p> <p class="style1B"> Style 1B </p> <p class="style2"> Style 2 </p> </body> </html> Depois que o objeto HTMLLoader carregar esse conteúdo, você poderá manipular os estilos CSS da página, através da matriz cssRules da matriz window.document.styleSheets, como mostrado a seguir: var html:HTMLLoader = new HTMLLoader( ); var urlReq:URLRequest = new URLRequest("test.html"); html.load(urlReq); html.addEventListener(Event.COMPLETE, completeHandler); function completeHandler(event:Event):void { var styleSheet0:Object = html.window.document.styleSheets[0]; styleSheet0.cssRules[0].style.fontSize = "32px"; styleSheet0.cssRules[1].style.color = "#FF0000"; var styleSheet1:Object = html.window.document.styleSheets[1]; styleSheet1.cssRules[0].style.color = "blue"; styleSheet1.cssRules[0].style.font-family = "Monaco"; } Esse código ajusta os estilos CSS para que o documento HTML resultante tenha a seguinte aparência: Lembre-se de que esse código pode adicionar estilos à página após o objeto HTMLLoader despachar o evento complete. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 248 Programação em HTML e JavaScript Conteúdo entre scripts em caixas de proteção de segurança distintas O modelo de segurança de tempo de execução isola o código de origens distintas. Cruzando scripts de conteúdo em caixas de proteção de segurança distintas, você pode permitir que o conteúdo de uma caixa de proteção de segurança acesse as propriedades e os métodos selecionados em outra caixa de proteção. Caixas de proteção de segurança do AIR e código JavaScript O AIR aplica a política de mesma origem, que impede a interação de código de um domínio com o conteúdo de outro domínio. Todos os arquivos são colocados em uma caixa de proteção com base nas respectivas origens. Normalmente, o conteúdo na caixa de proteção do aplicativo não pode violar o princípio de mesma origem e o conteúdo entre scripts, carregado de fora do diretório de instalação do aplicativo. No entanto, o AIR oferece algumas técnicas que permitem o cruzamento de scripts em conteúdo "não aplicativo". Uma das técnicas usa frames ou iframes para mapear conteúdo de aplicativo em uma caixa de proteção de segurança distinta. Qualquer página carregada da área com caixa de proteção do aplicativo se comporta como se tivesse sido carregada do domínio remoto. Por exemplo, mapeando o conteúdo do aplicativo para o domínio example.com, esse conteúdo pode fazer o cruzamento entre scripts das páginas carregadas desse domínio. Como essa técnica coloca o conteúdo do aplicativo em uma caixa de proteção distinta, o código nesse conteúdo também não estará mais sujeito às restrições na execução de código em strings avaliadas. Você pode usar essa técnica de mapeamento de caixa de proteção para para atenuar essas restrições, mesmo quando não for necessário fazer o cruzamento de scripts de conteúdo remoto. Mapear conteúdo dessa maneira pode ser muito útil ao trabalhar com uma das várias estruturas JavaScript ou com código existente que dependa das strings de avaliação. No entanto, você deve considerar e se proteger contra o risco adicional de que algum conteúdo não confiável possa ser injetado e executado quando o conteúdo for executado fora da caixa de proteção do aplicativo. Ao mesmo tempo, o conteúdo de aplicativo mapeado para uma outra caixa de proteção perde o acesso às APIs do AIR, portanto, a técnica de mapeamento de caixa de proteção não pode ser usada para expor a funcionalidade do AIR ao código executado fora da caixa de proteção do aplicativo. Outra técnica de cruzamento de scripts permite criar uma interface chamada ponte de caixa de proteção entre o conteúdo de uma caixa de proteção "não aplicativo" e seu documento pai na caixa de proteção do aplicativo. A ponte permite que o conteúdo filho acesse as propriedades e os métodos definidos pelo pai e o pai acesse as propriedades e os métodos definidos pelo filho, ou ambos. Por fim, você também pode executar XMLHttpRequests entre domínios da caixa de proteção do aplicativo e, opcionalmente, de outras caixas de proteção. Para obter mais informações, consulte “Elementos HTML frame e iframe” na página 227, “segurança HTML” na página 30 e “O objeto XMLHttpRequest” na página 221. Carregamento de conteúdo do aplicativo em uma caixa de proteção "não aplicativo" Para permitir que o conteúdo do aplicativo faça cruzamento de script de conteúdo carregado de fora do diretório de instalação do aplicativo, você pode usar os elementos frame ou iframe para carregar conteúdo do aplicativo na mesma caixa de proteção de segurança do conteúdo externo. Se você não precisa fazer cruzamento de script de conteúdo remoto, mas ainda assim deseja carregar uma página do seu aplicativo fora da respectiva caixa de proteção, pode usar a mesma técnica, especificando http://localhost/ ou algum outro valor inócuo, como o domínio de origem. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 249 Programação em HTML e JavaScript O AIR adiciona os novos atributos sandboxRoot e documentRoot ao elemento frame que permite especificar se o arquivo do aplicativo carregado no frame deve ser mapeado para uma caixa de proteção "não aplicativo". Arquivos que estão sendo resolvidos em um caminho abaixo da URL sandboxRoot são carregados, em vez do diretório documentRoot. Para fins de segurança, o conteúdo do aplicativo carregado dessa maneira é tratado como se na verdade tivesse sido carregado da URL sandboxRoot. A propriedade sandboxRoot especifica a URL que deve ser usada para determinar a caixa de proteção e o domínio em que o conteúdo do quadro deve ser colocado. Os esquemas de URL file:, http: ou https: devem ser usados. Se você especificar uma URL relativa, o conteúdo permanecerá na caixa de proteção do aplicativo. A propriedade documentRoot especifica o diretório do qual o conteúdo do quadro deve ser carregado. Os esquemas de URL file:, app: ou app-storage: devem ser usados. O exemplo a seguir mapeia o conteúdo instalado no subdiretório sandbox do aplicativo a ser executado na caixa de proteção remota e o domínio www.example.com: <iframe src="http://www.example.com/local/ui.html" sandboxRoot="http://www.example.com/local/" documentRoot="app:/sandbox/"> </iframe> A página ui.html pode carregar um arquivo javascript da pasta sandbox local, usando a seguinte tag de script: <script src="http://www.example.com/local/ui.js"></script> Ele também pode carregar conteúdo de um diretório no servidor remoto usando uma tag de script como a que segue: <script src="http://www.example.com/remote/remote.js"></script> A URL sandboxRoot irá mascarar todo conteúdo na mesma URL do servidor remoto. No exemplo anterior, você não podia acessar nenhum conteúdo remoto em www.example.com/local/ (ou qualquer um de seus subdiretórios), pois o AIR remapeia a solicitação para o diretório local do aplicativo. As solicitações são remapeadas, sejam elas derivadas de navegação de página, de uma XMLHttpRequest ou de qualquer outro meio de carregamento de conteúdo. Configuração de interface de ponte de caixa de proteção Você pode usar uma ponte de caixa de proteção quando o conteúdo da caixa de proteção do aplicativo tiver que acessar propriedades ou métodos definidos pelo conteúdo em uma caixa de proteção "não aplicativo" , ou quando o conteúdo "não aplicativo" tiver que acessar propriedades e métodos definidos pelo conteúdo na caixa de proteção do aplicativo. Crie uma ponte com as propriedades childSandboxBridge e parentSandboxBridge do objeto window de algum documento filho. Estabelecimento de uma ponte de caixa de proteção filha A propriedade childSandboxBridge permite que o documento filho exponha uma interface para o conteúdo do documento pai. Para expor uma interface, você define a propriedade childSandbox como função ou objeto no documento filho. Em seguida, você pode acessar o objeto ou função do conteúdo no documento pai. O exemplo a seguir mostra como um script que está sendo executado em um documento filho pode expor um objeto contendo uma função e uma propriedade para o respectivo pai: var interface = {}; interface.calculatePrice = function(){ return ".45 cents"; } interface.storeID = "abc" window.childSandboxBridge = interface; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 250 Programação em HTML e JavaScript Se esse filho foi carregado em um iframe com id "filho" atribuída, você poderá acessar a interface do conteúdo pai, lendo a propriedade childSandboxBridge do quadro: var childInterface = document.getElementById("child").contentWindow.childSandboxBridge; air.trace(childInterface.calculatePrice()); //traces ".45 cents" air.trace(childInterface.storeID)); //traces "abc" Estabelecimento de uma ponte de caixa de proteção pai A propriedade parentSandboxBridge permite que o documento pai exponha uma interface para o conteúdo do documento filho. Para expor uma interface, o documento pai define a propriedade parentSandbox do documento filho como uma função ou objeto definido no documento pai. Em seguida, você pode acessar o objeto ou função do conteúdo no filho. O exemplo a seguir mostra como um script que está sendo executado em um quadro pai pode expor um objeto contendo uma função para um documento filho: var interface = {}; interface.save = function(text){ var saveFile = air.File("app-storage:/save.txt"); //write text to file } document.getElementById("child").contentWindow.parentSandboxBridge = interface; Ao usar essa interface, o conteúdo do quadro filho poderá salvar texto em um arquivo chamado save.txt, mas não terá nenhum outro acesso ao sistema de arquivos. O conteúdo filho poderá chamar a função save da seguinte maneira: var textToSave = "A string."; window.parentSandboxBridge.save(textToSave); O conteúdo do aplicativo deverá expor a interface mais estreita possível para as outras caixas de proteção. O conteúdo "não aplicativo" deve ser considerado não confiável inerentemente, já que ele pode estar sujeito à injeção de código acidental ou mal-intencionado. Você deve colocar as proteções apropriadas no local para impedir o uso inadequado da interface exposta através da ponte da caixa de proteção pai. Acesso à ponte de caixa de proteção pai durante o carregamento de página Para que o script de um documento filho acesse uma ponte de caixa de proteção pai, a ponte deve ser configurada antes que o script seja executado. Os objetos window, frame e iframe despacham o evento dominitialize quando uma nova página DOM tiver sido criada, mas antes que qualquer script tenha sido analisado ou que elementos DOM tenham sido adicionados. Você pode usar o evento dominitialize para estabelecer a ponte na seqüência de construção de página, cedo o bastante para que todos os scripts no documento filho possam acessá-la. O exemplo a seguir ilustra como criar uma ponte de caixa de proteção pai em resposta ao evento dominitialize despachado do quadro filho: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 251 Programação em HTML e JavaScript <html> <head> <script> var bridgeInterface = {}; bridgeInterface.testProperty = "Bridge engaged"; function engageBridge(){ document.getElementById("sandbox").contentWindow.parentSandboxBridge = bridgeInterface; } </script> </head> <body> <iframe id="sandbox" src="http://www.example.com/air/child.html" documentRoot="app:/" sandboxRoot="http://www.example.com/air/" ondominitialize="engageBridge()"/> </body> </html> O seguinte documento child.html ilustra como o conteúdo filho pode acessar a ponte de caixa de proteção pai: <html> <head> <script> document.write(window.parentSandboxBridge.testProperty); </script> </head> <body></body> </html> Para ouvir o evento dominitialize em uma janela filha, em vez de um quadro, você deve adicionar o ouvinte ao novo objeto window filho criado pela função window.open(): var childWindow = window.open(); childWindow.addEventListener("dominitialize", engageBridge()); childWindow.document.location = "http://www.example.com/air/child.html"; Nesse caso, não há como mapear o conteúdo do aplicativo para uma caixa de proteção "não aplicativo". Essa técnica só é útil quando child.html é carregado de fora do diretório do aplicativo. Você pode ainda mapear conteúdo do aplicativo na janela para uma caixa de proteção "não aplicativo", mas primeiramente, é preciso carregar uma página intermediária que use ela mesma quadros para carregar o documento filho e mapeá-lo para a caixa de proteção desejada. Se você usar a função createRootWindow() da classe HTMLLoader para criar uma janela, a nova janela não será filha do documento do qual createRootWindow() será chamado. Portanto, você não pode criar uma ponte de caixa de proteção da janela que faz a chamada para um conteúdo "não aplicativo" carregado na nova janela. Em vez disso, você deve carregar uma página intermediária na nova janela que use ela mesma quadros para carregar o documento filho. Em seguida, você pode estabelecer a ponte do documento pai da nova janela para o documento filho carregado no quadro. 252 Capítulo 22: Tratamento de eventos relacionados a HTML O sistema de tratamento de eventos permite que programadores respondam às entradas de usuários e eventos do sistema de forma conveniente. O modelo de evento do Adobe® AIR™ não é apenas conveniente, mas também compatível com os padrões. Com base na Especificação de eventos DOM (Modelo de objeto de documento) de Nível 3, uma arquitetura de tratamento de eventos padrão do segmento, o modelo de evento oferece uma ferramenta de tratamento de eventos eficiente e intuitiva para programadores. eventos HTMLLoader O objeto HTMLLoader despacha os seguintes eventos do Adobe® ActionScript®3.0: Evento Descrição htmlDOMInitialize Despachado quando o documento HTML é criado, mas antes que qualquer script seja analisado ou que os nós DOM sejam adicionados à página. complete Despachado quando o HTML DOM tiver sido criado em resposta à operação de carregamento, logo após o evento onload na página HTML. htmlBoundsChanged Despachado quando uma ou as duas propriedades contentWidth e contentHeight são alteradas. locationChange Despachado quando a propriedade location do HTMLLoader foi alterada. scroll Despachado a sempre que o mecanismo HTML altera a posição de rolagem. Eventos de rolagem podem ocorrer devido à navegação para ancorar links (nº de links) na página ou devido às chamadas do métodowindow.scrollTo(). Inserir texto em uma entrada de texto ou área de texto também pode gerar um evento de rolagem. uncaughtScriptException Despachado quando ocorre uma exceção JavaScript no HTMLLoader e a exceção não é capturada no código JavaScript. Você também pode registrar uma função ActionScript para o evento JavaScript (como onClick). Para obter detalhes, consulte “Tratamento de eventos DOM com o ActionScript” na página 252. Tratamento de eventos DOM com o ActionScript Você pode registrar as funções do ActionScript para que respondam a eventos JavaScript. Por exemplo, considere o seguinte conteúdo HTML: <html> <body> <a href="#" id="testLink">Click me.</a> </html> Você pode registrar uma função do ActionScript como manipulador de qualquer evento na página. Por exemplo, o código a seguir adiciona a função clickHandler() como o ouvinte do evento onclick do elemento testLink na página HTML: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 253 Tratamento de eventos relacionados a HTML var html:HTMLLoader = new HTMLLoader( ); var urlReq:URLRequest = new URLRequest("test.html"); html.load(urlReq); html.addEventListener(Event.COMPLETE, completeHandler); function completeHandler(event:Event):void { html.window.document.getElementById("testLink").onclick = clickHandler; } function clickHandler():void { trace("You clicked it!"); } Você também pode usar o método addEventListener() para se registrar para esses eventos. Por exemplo, você pode substituir o método completeHandler() no exemplo anterior pelo seguinte código: function completeHandler(event:Event):void { var testLink:Object = html.window.document.getElementById("testLink"); testLink.addEventListener("click", clickHandler); } Quando um ouvinte se refere a um elemento DOM específico, é bom aguardar que o HTMLLoader pai despache o evento complete antes de adicionar os ouvintes de evento. As páginas HTML com freqüência carregam vários arquivos e o HTML DOM não é criado totalmente até que todos os arquivos sejam carregados e analisados. O HTMLLoader despacha o evento complete quando todos os elementos tiverem sido criados. Resposta a exceções JavaScript não capturadas Considere o seguinte HTML: <html> <head> <script> function throwError() { var x = 400 * melbaToast; } </script> </head> <body> <a href="#" onclick="throwError()">Click me.</a> </html> Ele contém uma função JavaScript, throwError(), que faz referência a uma variável desconhecida, melbaToast: var x = 400 * melbaToast; Quando a operação de JavaScript encontra uma operação ilegal não capturada no código JavaScript com uma estrutura try/catch, o objeto HTMLLoader que contém a página despacha um evento HTMLUncaughtScriptExceptionEvent. Você pode registrar um manipulador para esse evento, como no código a seguir: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 254 Tratamento de eventos relacionados a HTML var html:HTMLLoader = new HTMLLoader(); var urlReq:URLRequest = new URLRequest("test.html"); html.load(urlReq); html.width = container.width; html.height = container.height; container.addChild(html); html.addEventListener(HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION, htmlErrorHandler); function htmlErrorHandler(event:HTMLUncaughtJavaScriptExceptionEvent):void { event.preventDefault(); trace("exceptionValue:", event.exceptionValue) for (var i:int = 0; i < event.stackTrace.length; i++) { trace("sourceURL:", event.stackTrace[i].sourceURL); trace("line:", event.stackTrace[i].line); trace("function:", event.stackTrace[i].functionName); } } No JavaScript, você pode tratar o mesmo evento usando a propriedade window.htmlLoader: <html> <head> <script language="javascript" type="text/javascript" src="AIRAliases.js"></script> <script> function throwError() { var x = 400 * melbaToast; } function htmlErrorHandler(event) { event.preventDefault(); var message = "exceptionValue:" + event.exceptionValue + "\n"; for (var i = 0; i < event.stackTrace.length; i++){ message += "sourceURL:" + event.stackTrace[i].sourceURL +"\n"; message += "line:" + event.stackTrace[i].line +"\n"; message += "function:" + event.stackTrace[i].functionName + "\n"; } alert(message); } window.htmlLoader.addEventListener("uncaughtScriptException", htmlErrorHandler); </script> </head> <body> <a href="#" onclick="throwError()">Click me.</a> </html> O manipulador de eventos htmlErrorHandler() cancela o comportamento padrão do evento (que é enviar a mensagem de erro de JavaScript para a saída trace do AIR) e gera sua própria mensagem de saída. Ele produz o valor do exceptionValue do objeto HTMLUncaughtScriptExceptionEvent. Ele produz as propriedades de cada objeto na matriz stackTrace: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 255 Tratamento de eventos relacionados a HTML exceptionValue: ReferenceError: Can't find variable: melbaToast sourceURL: app:/test.html line: 5 function: throwError sourceURL: app:/test.html line: 10 function: onclick Tratamento de eventos de tempo de execução com JavaScript As classes de tempo de execução oferecem suporte à adição de manipuladores de eventos com o método addEventListener(). Para adicionar uma função do manipulador a um evento, chame o método addEventListener() do objeto que despacha o evento, fornecendo o tipo de evento e a função de tratamento. Por exemplo, para ouvir o evento closing despachado quando o usuário clica no botão Fechar da janela na barra de título, use a seguinte instrução: window.nativeWindow.addEventListener(air.NativeWindow.CLOSING, handleWindowClosing); Criação de função do manipulador de eventos O código a seguir cria um arquivo HTML simples que exibe informações sobre a posição da janela principal. A função do manipulador, chamada de moveHandler(), ouve o evento move (definido pela classe NativeWindowBoundsEvent) da janela principal. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 256 Tratamento de eventos relacionados a HTML <html> <script src="AIRAliases.js" /> <script> function init() { writeValues(); window.nativeWindow.addEventListener(air.NativeWindowBoundsEvent.MOVE, moveHandler); } function writeValues() { document.getElementById("xText").value = window.nativeWindow.x; document.getElementById("yText").value = window.nativeWindow.y; } function moveHandler(event) { air.trace(event.type); // move writeValues(); } </script> <body onload="init()" /> <table> <tr> <td>Window X:</td> <td><textarea id="xText"></textarea></td> </tr> <tr> <td>Window Y:</td> <td><textarea id="yText"></textarea></td> </tr> </table> </body> </html> Quando o usuário move a janela, os elementos da área de texto exibem as posições X e Y atualizadas da janela: Observe que o objeto de evento é passado como argumento para o método moveHandler(). O parâmetro event permite que a função do manipulador examine o objeto de evento. Neste exemplo, você usa a propriedade type do objeto de evento para informar que o evento é um evento move. Remoção de ouvintes de eventos Você pode usar o método removeEventListener() para remover um ouvinte de evento que não seja mais necessário. É uma boa idéia remover o ouvinte que não será mais usado. Entre os parâmetros obrigatórios estão eventName e listener, que são os mesmos parâmetros obrigatórios no método addEventListener(). Remoção de ouvintes de eventos nas páginas HTML que navegam Quando o conteúdo HTML é navegado ou quando é descartado porque a janela que o contém é fechada, os ouvintes de eventos que fazem referência a objetos na página não carregada não são removidos automaticamente. Quando o objeto despacha um evento para um manipulador que já foi descarregado, você obtém a seguinte mensagem de erro: "O aplicativo tentou fazer referência a um objeto JavaScript em uma página HTML que não é mais carregada". Para evitar esse tipo de erro, remova os ouvintes de eventos JavaScript da página HTML antes que ele parta. No caso de navegação de página (em um objeto HTMLLoader), remova o ouvinte de evento durante o evento unload do objeto window. Por exemplo, o código JavaScript a seguir remove um ouvinte de evento de um evento uncaughtScriptException: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 257 Tratamento de eventos relacionados a HTML window.onunload = cleanup; window.htmlLoader.addEventListener('uncaughtScriptException', uncaughtScriptException); function cleanup() { window.htmlLoader.removeEventListener('uncaughtScriptException', uncaughtScriptExceptionHandler); } Para impedir que o erro ocorra ao fechar janelas que contêm esse conteúdo HTML, chame uma função de limpeza em resposta ao evento closing do objeto NativeWindow (window.nativeWindow). Por exemplo, o código JavaScript a seguir remove um ouvinte de evento de um evento uncaughtScriptException: window.nativeWindow.addEventListener(air.Event.CLOSING, cleanup); function cleanup() { window.htmlLoader.removeEventListener('uncaughtScriptException', uncaughtScriptExceptionHandler); } Você também pode impedir que esse erro ocorra removendo o ouvinte de evento assim que ele for executado. Por exemplo, o código JavaScript a seguir cria uma janela html chamando o método createRootWindow() da classe HTMLLoader e adiciona um ouvinte de evento ao evento complete. Quando o manipulador de eventos complete é chamado, ele remove o próprio ouvinte de evento usando a função removeEventListener(): var html = runtime.flash.html.HTMLLoader.createRootWindow(true); html.addEventListener('complete', htmlCompleteListener); function htmlCompleteListener() { html.removeEventListener(complete, arguments.callee) // handler code.. } html.load(new runtime.flash.net.URLRequest("second.html")); Remover ouvintes de evento desnecessários também permite que o coletor de lixo do sistema recupere qualquer memória associada a esses ouvintes. Verificação de ouvintes de eventos existentes O método hasEventListener() permite verificar a existência de um ouvinte de evento em um objeto. 258 Capítulo 23: Gravação de script de contêiner HTML A classe HTMLLoader funciona como o contêiner de conteúdo HTML no Adobe® AIR™. A classe oferece várias propriedades e métodos, herdados da classe Sprite, para controlar o comportamento e a aparência do objeto na lista de exibição do ActionScript® 3.0. Além disso, a classe define propriedades e métodos de tarefas, como carregamento e interação com conteúdo HTML e gerenciamento de histórico. A classe HTMLHost define um conjunto de comportamentos padrão de um HTMLLoader. Quando você cria um objeto HTMLLoader, nenhuma implementação HTMLHost é fornecida. Portanto, quando o conteúdo HTML aciona um dos comportamentos padrão, como alteração de localização da janela ou do título da janela, não acontece nada. Você pode estender a classe HTMLHost para definir os comportamentos desejados para o aplicativo. Uma implementação padrão do HTMLHost é fornecida para janelas HTML criadas pelo AIR. Você pode atribuir a implementação HTMLHost padrão a outro objeto HTMLLoader definindo a propriedade htmlHost do objeto, usando um novo objeto HTMLHost criado com o parâmetro defaultBehavior definido como true. Exibição de propriedades de objetos HTMLLoader O objeto HTMLLoader herda as propriedades de exibição da classe Sprite do Adobe® Flash® Player. Você pode redimensionar, mover, ocultar e alterar a cor do plano de fundo, por exemplo. Ou, pode aplicar efeitos avançadas, como filtros, máscaras, dimensionamento e rotação. Ao aplicar efeitos, considere o impacto sobre a legibilidade. O conteúdo SWF e PDF carregado em uma página HTML não pode ser exibido quando alguns efeitos são aplicados. As janelas HTML contêm um objeto HTMLLoader que processa conteúdo HTML. Esse objeto fica restrito dentro da área da janela, portanto, alterar dimensões, posição, rotação ou fato de dimensionamento nem sempre produz os resultados desejados. Propriedades básicas de exibição As propriedades básicas de exibição do HTMLLoader permitem posicionar o controle no respectivo objeto de exibição pai para definir o tamanho e mostrar ou ocultar o controle. Você não deve alterar essas propriedades do objeto HTMLLoader de uma janela HTML. As propriedades básicas incluem: Propriedade Observações x, y Posiciona o objeto em seu contêiner pai. width, height Altera as dimensões da área de exibição. visible Controla a visibilidade do objeto e todo seu conteúdo. Fora da janela HTML, as propriedades width e height do objeto HTMLLoader assumem o padrão 0. Você deve definir a largura e a altura para que o conteúdo HTML carregado possa ser visualizado. O conteúdo HTML é desenhado no tamanho do HTMLLoader, disposto de acordo com as propriedades HTML e CSS do conteúdo. Alterar o tamanho do HTMLLoader redireciona o conteúdo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 259 Gravação de script de contêiner HTML Ao carregar conteúdo em um novo objeto HTMLLoader (com width ainda definido como 0), pode ser tentador definir width e height de exibição do HTMLLoader usando as propriedades contentWidth e contentHeight. Essa técnica funciona em páginas com largura mínima razoável quando disposta de acordo com as regras de fluxo de HTML e CSS. No entanto, algumas páginas resultam em um layout longo e estreito na ausência de uma largura razoável fornecida pelo HTMLLoader. Nota: Quando você altera a largura e a altura do objeto HTMLLoader, os valores scaleX e scaleY não são alterados, como ocorreria com a maioria dos demais tipos de objetos de exibição. Transparência de conteúdo HTMLLoader A propriedade paintsDefaultBackground do objeto HTMLLoader, que é true por padrão, determina se o objeto HTMLLoader desenha um plano de fundo opaco. Quando paintsDefaultBackground for false, o plano de fundo ficará claro. O contêiner do objeto de exibição ou outros objetos de exibição abaixo do objeto HTMLLoader ficam visíveis por trás dos elementos de primeiro plano do conteúdo HTML. Se o elemento body ou qualquer outro elemento do documento HTML especificar uma cor de plano de fundo (usando style="background-color:gray", por exemplo), o plano de fundo dessa parte do HTML ficará opaco e será processado com a cor de plano de fundo especificada. Se você definir a propriedade opaqueBackground do objeto HTMLLoader e paintsDefaultBackground for false, a cor definida para opaqueBackground ficará visível. Nota: Você pode usar um gráfico com formato PNG transparente para dar ao elemento no documento HTML um plano de fundo de mesclagem de alfa. Não há suporte para a configuração de estilo de opacidade de elemento HTML. Dimensionamento de conteúdo HTMLLoader Evite o dimensionamento do objeto HTMLLoader além do fator de dimensionamento de 1.0. O texto no conteúdo HTMLLoader é processado em uma resolução específica e aparecerá pixelizado se o objeto HTMLLoader for dimensionado. Para evitar que o HTMLLoader, bem como o respectivo conteúdo, sejam dimensionados quando a janela for redimensionada, defina a propriedade scaleMode do Palco como StageScaleMode.NO_SCALE. Considerações ao carregar conteúdo SWF ou PDF em uma página HTML O conteúdo SWF e PDF carregado em um objeto HTMLLoader desaparece nas seguintes condições: • Se você dimensionar o objeto HTMLLoader em um outro fator que não 1.0. • Se você definir a propriedade alfa do objeto HTMLLoader em um outro valor que não 1.0. • Se você girar o conteúdo HTMLLoader. O conteúdo reaparecerá se você remover a configuração da propriedade ofensiva e os filtros ativos. Nota: O tempo de execução não pode exibir conteúdo SWF ou PDF em janelas transparentes. Para obter mais informações sobre o carregamento desses tipos de mídia no HTMLLoader, consulte “Incorporação de conteúdo SWF em HTML” na página 244 e “Adição de conteúdo em PDF” na página 272. Propriedades avançadas de exibição A classe HTMLLoader herda vários métodos que podem ser usados em efeitos especiais. Em geral, esses efeitos têm limitações quando usados com a exibição HTMLLoader, mas podem ser úteis em transições ou outros efeitos temporários. Por exemplo, se você exibe uma janela de diálogo para coletar entradas de usuário, é possível desfocar a exibição da janela principal até que o usuário feche a caixa de diálogo. Da mesma forma, você pode fazer a exibição desaparecer gradualmente ao fechar uma janela. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 260 Gravação de script de contêiner HTML As propriedades avançadas de exibição incluem: Propriedade Limitações alpha Pode reduzir a legibilidade do conteúdo HTML. filters Em uma Janela HTML, os efeitos exteriores são recortados pela borda da janela. graphics As formas desenhadas com comandos gráficos aparecem abaixo do conteúdo HTML, incluindo o plano de fundo padrão. A propriedade paintsDefaultBackground deve ser false para que as formas do desenho estejam visíveis. opaqueBackground Não altera a cor do plano de fundo padrão. A propriedade paintsDefaultBackground deve ser false para que essa camada de cor esteja visível. rotation Os cantos da área retangular do HTMLLoader podem ser recortados pela borda da janela. O conteúdo SWF e PDF carregado no conteúdo HTML não é exibido. scaleX e scaleY A exibição processada pode aparecer pixelizada em fatores de dimensionamento maiores que 1. O conteúdo SWF e PDF carregado no conteúdo HTML não é exibido. transform Pode reduzir a legibilidade do conteúdo HTML. A exibição HTML pode ser recortada pela borda da janela. O conteúdo SWF e PDF carregado no conteúdo HTML não será exibido se a transformação envolver rotação, dimensionamento ou inclinação. O exemplo a seguir ilustra como definir a matriz filters para desfocar a exibição HTML inteira: var html:HTMLLoader = new HTMLLoader(); var urlReq:URLRequest = new URLRequest("http://www.adobe.com/"); html.load(urlReq); html.width = 800; html.height = 600; var blur:BlurFilter = new BlurFilter(8); var filters:Array = [blur]; html.filters = filters; Rolagem de conteúdo HTML A classe HTMLLoader inclui as seguintes propriedades que permitem controlar a rolagem de conteúdo HTML: Propriedade Descrição contentHeight A altura, em pixels, do conteúdo HTML. contentWidth A largura, em pixels, do conteúdo HTML. scrollH A posição da barra de rolagem horizontal do conteúdo HTML no objeto HTMLLoader. scrollV A posição da barra de rolagem vertical do conteúdo HTML no objeto HTMLLoader. O código a seguir define a propriedade scrollV, de modo que o conteúdo HTML seja rolado para a parte inferior da página: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 261 Gravação de script de contêiner HTML var html:HTMLLoader = new HTMLLoader(); html.addEventListener(Event.HTML_BOUNDS_CHANGE, scrollHTML); const SIZE:Number = 600; html.width = SIZE; html.height = SIZE; var urlReq:URLRequest = new URLRequest("http://www.adobe.com"); html.load(urlReq); this.addChild(html); function scrollHTML(event:Event):void { html.scrollV = html.contentHeight - SIZE; } O HTMLLoader não inclui barras de rolagem horizontal e vertical. Você pode implementar barras de rolagem no ActionScript. Você também pode usar o método HTMLLoader.createRootWindow() para criar uma janela contendo um objeto HTMLLoader com barras de rolagem (consulte “Criação de janelas com conteúdo HTML de rolagem” na página 270). Acesso à lista de histórico de HTML À medida que novas páginas são carregadas no objeto HTMLLoader, o tempo de execução mantém uma lista de histórico do objeto. A lista de histórico corresponde ao objeto window.history na página HTML. A classe HTMLLoader inclui as seguintes propriedades e métodos que permitem trabalhar com a lista de histórico de HTML: Membro de classe Descrição historyLength O comprimento geral da lista de histórico, incluindo entradas dianteiras e traseiras. historyPosition A posição atual na lista de histórico. Os itens de histórico antes dessa posição representam navegação "para trás" e itens após essa posição representam navegação “para frente”. getHistoryAt() Retorna o objeto URLRequest correspondente à entrada de histórico na posição especificada na lista de histórico. historyBack() Navega para trás na lista de histórico, se possível. historyForward() Navega para frente na lista de histórico, se possível. historyGo() Navega o número indicado de etapas no histórico do navegador. Navega para frente, se for positivo, e para trás, se for negativo. Navegar para zero recarrega a página. Especificar uma posição além do final, navega para o final da lista. Os itens da lista de histórico são armazenados como objetos do tipo HistoryListItem. A classe HistoryListItem tem as seguintes propriedades: Propriedade Descrição isPost Defina como true se a página HTML incluir dados POST. originalUrl A URL original da página HTML antes de qualquer redirecionamento. título O título da página HTML. url A URL da página HTML. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 262 Gravação de script de contêiner HTML Definição do agente do usuário usado ao carregar conteúdo HTML A classe HTMLLoader tem a propriedade userAgent, que permite definir a seqüência de agente do usuário usada pelo HTMLLoader. Defina a propriedade userAgent do objeto HTMLLoader antes de chamar o método load(). Se você definir esta propriedade na ocorrência HTMLLoader, a propriedade userAgent do URLRequest passada para o método load()não será usada. Você pode definir a string de agente do usuário padrão usada por todos os objetos HTMLLoader em um domínio de aplicativo, configurando a propriedade URLRequestDefaults.userAgent. As propriedades URLRequestDefaults estáticas são aplicadas como padrão a todos os objetos URLRequest, não apenas aos URLRequests usados com o método load() dos objetos HTMLLoader. Configurar a propriedade userAgent do HTMLLoader substitui a configuração URLRequestDefaults.userAgent padrão. Se você não definir um valor de agente do usuário para a propriedade userAgent do objeto HTMLLoader ou para URLRequestDefaults.userAgent, o valor de agente do usuário AIR padrão será usado. Esse valor padrão varia em função do sistema operacional do tempo de execução (tal como Mac OS ou Windows), do idioma do tempo de execução e da versão, como nos dois exemplos a seguir: • "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/420+ (KHTML, como Gecko) AdobeAIR/1.0" • "Mozilla/5.0 (Windows; U; en) AppleWebKit/420+ (KHTML, como Gecko) AdobeAIR/1.0" Configuração de codificação de caractere para uso de conteúdo HTML. A página HTML pode especificar a codificação de caractere por ela usado, incluindo a tag meta, como a seguir: meta http-equiv="content-type" content="text/html" charset="ISO-8859-1"; Substitua a configuração da página para assegurar que a codificação de caractere específica seja usada, configurando a propriedade textEncodingOverride do objeto HTMLLoader: var html:HTMLLoader = new HTMLLoader(); html.textEncodingOverride = "ISO-8859-1"; Especifique a codificação de caractere do conteúdo HTMLLoader que deverá ser usada quando a página HTML não especificar uma configuração com a propriedade textEncodingFallback do objeto HTMLLoader: var html:HTMLLoader = new HTMLLoader(); html.textEncodingFallback = "ISO-8859-1"; A propriedade textEncodingOverride substitui a configuração da página HTML. E a propriedade textEncodingOverride e a configuração da página HTML substituem a propriedade textEncodingFallback. Defina a propriedade textEncodingOverride ou a propriedade textEncodingFallback antes de carregar conteúdo HTML. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 263 Gravação de script de contêiner HTML Definição de interfaces do usuário como navegadores para conteúdo HTML O JavaScript oferece diversas APIs para controlar a janela que exibe o conteúdo HTML. No AIR, essas APIs podem ser substituídas implementando uma classe HTMLHost personalizada. Sobre estender a classe HTMLHost Se, por exemplo, o aplicativo apresentar vários objetos HTMLLoader em uma interface com abas, talvez você deseje que as alterações feitas pelas páginas HTML carregadas alterem o rótulo da aba e não o título da janela principal. Da mesma forma, o código pode responder a uma chamada window.moveTo() reposicionando o objeto HTMLLoader no respectivo contêiner do objeto de exibição pai, movendo a janela que contém o objeto HTMLLoader, não fazendo exatamente nada ou fazendo alguma outra coisa por completo. A classe HTMLHost do AIR controla as seguintes propriedades e métodos JavaScript: • window.status • window.document.title • window.location • window.blur() • window.close() • window.focus() • window.moveBy() • window.moveTo() • window.open() • window.resizeBy() • window.resizeTo() Quando você cria um objeto HTMLLoader usando new HTMLLoader(), as propriedades ou métodos JavaScript listados não são ativados. A classe HTMLHost oferece uma implementação padrão como navegador dessas APIs JavaScript. Você também pode estender a classe HTMLHost para personalizar o comportamento. Para criar um objeto HTMLHost que ofereça suporte ao comportamento padrão, defina o parâmetro defaultBehaviors como true no construtor HTMLHost: var defaultHost:HTMLHost = new HTMLHost(true); Quando você cria uma janela HTML no AIR com o método createRootWindow() da classe HTMLLoader, uma ocorrência HTMLHost com suporte aos comportamentos padrão é atribuída automaticamente. Você pode alterar o comportamento do objeto host atribuindo uma implementação HTMLHost diferente à propriedade htmlHost do HTMLLoader ou, pode atribuir null para desativar os recursos completamente. Nota: O AIR atribui um objeto HTMLHost padrão à janela inicial criada para o aplicativo AIR baseado em HTML e qualquer janela criada pela implementação padrão do método window.open() de JavaScript. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 264 Gravação de script de contêiner HTML Exemplo: Extensão da classe HTMLHost O exemplo a seguir mostra como personalizar a maneira como o objeto HTMLLoader afeta a interface do usuário, estendendo a classe HTMLHost: 1 Crie um arquivo Flash para o AIR. Defina a classe do documento como CustomHostExample e, em seguida, salve o arquivo como CustomHostExample.fla. 2 Crie um arquivo ActionScript chamado CustomHost.as contendo uma classe que estenda a classe HTMLHost (uma subclasse). Essa classe substitui certos métodos da nova classe para tratar alterações nas configurações relacionadas à interface do usuário. Por exemplo, a classe a seguir, CustomHost, define comportamentos de chamadas parawindow.open() e altera para window.document.title. As chamadas para o método window.open() abrem a página HTML em uma nova janela e alterações na propriedade window.document.title (incluindo a configuração do elemento <title> da página HTML) definem o título dessa janela. package { import import import import import import import import import import flash.display.StageScaleMode; flash.display.NativeWindow; flash.display.NativeWindowInitOptions; flash.events.Event; flash.events.NativeWindowBoundsEvent; flash.geom.Rectangle; flash.html.HTMLLoader; flash.html.HTMLHost; flash.html.HTMLWindowCreateOptions; flash.text.TextField; public class CustomHost extends HTMLHost { public var statusField:TextField; public function CustomHost(defaultBehaviors:Boolean=true) { super(defaultBehaviors); } override public function windowClose():void { htmlLoader.stage.nativeWindow.close(); } override public function createWindow( windowCreateOptions:HTMLWindowCreateOptions ):HTMLLoader { var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); var bounds:Rectangle = new Rectangle(windowCreateOptions.x, windowCreateOptions.y, windowCreateOptions.width, windowCreateOptions.height); var htmlControl:HTMLLoader = HTMLLoader.createRootWindow(true, initOptions, windowCreateOptions.scrollBarsVisible, bounds); htmlControl.htmlHost = new HTMLHostImplementation(); if(windowCreateOptions.fullscreen){ htmlControl.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; } return htmlControl; DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 265 Gravação de script de contêiner HTML } override public function updateLocation(locationURL:String):void { trace(locationURL); } override public function set windowRect(value:Rectangle):void { htmlLoader.stage.nativeWindow.bounds = value; } override public function updateStatus(status:String):void { statusField.text = status; trace(status); } override public function updateTitle(title:String):void { htmlLoader.stage.nativeWindow.title = title + "- Example Application"; } override public function windowBlur():void { htmlLoader.alpha = 0.5; } override public function windowFocus():void { htmlLoader.alpha = 1; } } } 3 Crie outro arquivo ActionScript chamado CustomHostExample.as para conter a classe de documento do aplicativo. Essa classe cria um objeto HTMLLoader e define a respectiva propriedade host como uma ocorrência da classe CustomHost definida na etapa anterior: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 266 Gravação de script de contêiner HTML package { import import import import flash.display.Sprite; flash.html.HTMLLoader; flash.net.URLRequest; flash.text.TextField; public class CustomHostExample extends Sprite { function CustomHostExample():void { var html:HTMLLoader = new HTMLLoader(); html.width = 550; html.height = 380; var host:CustomHost = new CustomHost(); html.htmlHost = host; var urlReq:URLRequest = new URLRequest("Test.html"); html.load(urlReq); addChild(html); var statusTxt:TextField = new TextField(); statusTxt.y = 380; statusTxt.height = 20; statusTxt.width = 550; statusTxt.background = true; statusTxt.backgroundColor = 0xEEEEEEEE; addChild(statusTxt); host.statusField = statusTxt; } } } Para testar o código descrito aqui, inclua um arquivo HTML com o seguinte conteúdo no diretório do aplicativo: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 267 Gravação de script de contêiner HTML <html> <head> <title>Test</title> <script> function openWindow() { document.title = "Test" window.open('Test.html'); } </script> </head> <body bgColor="#EEEEEE"> <a href="#" onclick="window.open('Test.html')">window.open('Test.html')</a> <br/><a href="#" onclick="window.document.location='http://www.adobe.com'"> window.document.location = 'http://www.adobe.com'</a> <br/><a href="#" onclick="window.moveBy(6, 12)">moveBy(6, 12)</a> <br/><a href="#" onclick="window.close()">window.close()</a> <br/><a href="#" onclick="window.blur()">window.blur()</a> <br/><a href="#" onclick="window.focus()">window.focus()</a> <br/><a href="#" onclick="window.status = new Date().toString()">window.status=new Date().toString()</a> </body> </html> Tratamento de alterações na propriedade window.location Substitua o método locationChange() para tratar alterações da URL da página HTML. O método locationChange() é chamado quando o JavaScript em uma página altera o valor de window.location. O exemplo a seguir simplesmente carrega a URL solicitada: override public function updateLocation(locationURL:String):void { htmlLoader.load(new URLRequest(locationURL)); } Nota: Você pode usar a propriedade htmlLoader do objeto HTMLHost para fazer referência ao objeto HTMLLoader atual. Tratamento de chamadas de JavaScript de window.moveBy(), window.moveTo(), window.resizeTo() e window.resizeBy() Substitua o método set windowRect() para tratar alterações nos limites do conteúdo HTML. O método set windowRect() é chamado quando o JavaScript em uma página chama window.moveBy(), window.moveTo(), window.resizeTo() ou window.resizeBy(). O exemplo a seguir simplesmente atualiza os limites da janela da área de trabalho: override public function set windowRect(value:Rectangle):void { htmlLoader.stage.nativeWindow.bounds = value; } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 268 Gravação de script de contêiner HTML Tratamento de chamadas JavaScript de window.open() Substitui o método createWindow() para tratar chamadas JavaScript de window.open(). As implementações do método createWindow() são responsáveis pela criação e retorno de um novo objeto HTMLLoader. Normalmente você exibe o HTMLLoader em uma nova janela, mas não é necessário criar uma nova janela. O exemplo a seguir ilustra como implementar a função createWindow() usando HTMLLoader.createRootWindow() para criar a janela e o objeto HTMLLoader. Você também pode criar o objeto NativeWindow separadamente e adicionar o HTMLLoader ao palco da janela. override public function createWindow(windowCreateOptions:HTMLWindowCreateOptions):HTMLLoader{ var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); var bounds:Rectangle = new Rectangle(windowCreateOptions.x, windowCreateOptions.y, windowCreateOptions.width, windowCreateOptions.height); var htmlControl:HTMLLoader = HTMLLoader.createRootWindow(true, initOptions, windowCreateOptions.scrollBarsVisible, bounds); htmlControl.htmlHost = new HTMLHostImplementation(); if(windowCreateOptions.fullscreen){ htmlControl.stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE; } return htmlControl; } Nota: Esse exemplo atribui a implementação HTMLHost personalizada a qualquer janela nova criada com window.open(). Você também pode usar uma implementação diferente ou definir a propriedade htmlHost como null em novas janelas, se desejar. O objeto passado como parâmetro para o método createWindow() é o objeto HTMLWindowCreateOptions. A classe HTMLWindowCreateOptions inclui propriedades que informam os valores definidos na seqüência de parâmetro features na chamada de window.open(): propriedade HTMLWindowCreateOptions Configuração correspondente na string de recursos na chamada JavaScript para window.open() fullscreen fullscreen height height locationBarVisible location menuBarVisible menubar resizeable resizable scrollBarsVisible scrollbars statusBarVisible status toolBarVisible toolbar width width x left ou screenX y top ou screenY A classe HTMLLoader não implementa todos os recursos que podem ser especificados na string de recursos. O aplicativo deve fornecer barras de rolagem, barras de localização, barras de menu, barras de status e barras de ferramentas, quando apropriado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 269 Gravação de script de contêiner HTML Os outros argumentos para o método window.open() de JavaScript são tratados pelo sistema. A implementação createWindow() não deve carregar conteúdo no objeto HTMLLoader nem definir o título da janela. Tratamento de chamadas JavaScript de window.close() Substitui o método windowClose() para tratar chamadas JavaScript do método window.close(). O exemplo a seguir fecha a janela da área de trabalho quando o método window.close() é chamado: override public function windowClose():void { htmlLoader.stage.nativeWindow.close(); } As chamadas JavaScript de window.close() não têm que fechar as janelas que as contêm. Você pode, por exemplo, remover o HTMLLoader da lista de exibição, deixando a janela (que pode ter outro conteúdo) aberta, conforme o código a seguir: override public function windowClose():void { htmlLoader.parent.removeChild(htmlLoader); } Tratamento de alterações da propriedade windows.status Substitua o método updateStatus() para tratar alterações JavaScript no valor de window.status. O exemplo a seguir rastreia o valor do status: override public function updateStatus(status:String):void { trace(status); } O status solicitado é passado como string para o método updateStatus(). O objeto HTMLLoader não oferece uma barra de status. Tratamento de alterações da propriedade window.document.title Substitua o método updateTitle() para tratar alterações JavaScript no valor de window.document.title. O exemplo a seguir altera o título da janela e acrescenta a seqüência, "Sample", ao título: override public function updateTitle(title:String):void { htmlLoader.stage.nativeWindow.title = title + " - Sample"; } Quando document.title estiver definido em uma página HTML, o título solicitado será passado como string para o método updateTitle(). As alterações em document.title não devem alterar o título da janela que contém o objeto HTMLLoader. Você pode, por exemplo, alterar outro elemento de interface, como campo de texto. Tratamento de chamadas JavaScript de window.blur() e window.focus() Substitua os métodos windowBlur() e windowFocus() para tratar chamadas JavaScript dewindow.blur() e window.focus(), conforme mostrado o exemplo a seguir: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 270 Gravação de script de contêiner HTML override public function windowBlur():void { htmlLoader.alpha = 0.5; } override public function windowFocus():void { htmlLoader.alpha = 1.0; NativeApplication.nativeApplication.activate(htmlLoader.stage.nativeWindow); } Nota: O AIR não fornece nenhuma API para desativar janela nem aplicativo. Criação de janelas com conteúdo HTML de rolagem A classe HTMLLoader inclui um método estático, HTMLLoader.createRootWindow(), que permite abrir uma nova janela (representada por um objeto NativeWindow) que contém um objeto HTMLLoader e define algumas configurações da interface do usuário para essa janela. O método tem quatro parâmetros que permitem definir a interface do usuário: Parâmetro Descrição visible Um valor booleano que especifica se a janela ficará inicialmente visível (true) ou não (false). windowInitOptions Um objeto NativeWindowInitOptions. A classe NativeWindowInitOptions define as opções de inicialização do objeto NativeWindow, incluindo o seguinte: se a janela é minimizável, maximizável ou redimensionável, se a janela tem cromo do sistema ou cromo personalizado, se a janela é transparente ou não (para janelas que não usam o cromo do sistema) e o tipo de janela. scrollBarsVisible Se há barras de rolagem (true) ou não (false). bounds Um objeto Rectangle definindo a posição e o tamanho da nova janela. Por exemplo, o código a seguir usa o método HTMLLoader.createRootWindow() para criar uma janela com conteúdo HTMLLoader que usa barras de rolagem: var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); var bounds:Rectangle = new Rectangle(10, 10, 600, 400); var html2:HTMLLoader = HTMLLoader.createRootWindow(true, initOptions, true, bounds); var urlReq2:URLRequest = new URLRequest("http://www.example.com"); html2.load(urlReq2); html2.stage.nativeWindow.activate(); Nota: Janelas criadas chamando createRootWindow() diretamente em JavaScript permanecem independentes da janela HTML aberta. As propriedades opener e parent da janela JavaScript, por exemplo, são null. No entanto, se você chamar createRootWindow() indiretamente substituindo o método createWindow() do HTMLHost para chamar createRootWindow(), opener e parent farão referência à janela HTML aberta. Criação de subclasses da classe HTMLLoader Você pode criar uma subclasse da classe HTMLLoader para criar novos comportamentos. Por exemplo, você pode criar uma subclasse que defina ouvintes de evento padrão de eventos HTMLLoader (como os eventos despachados quando o HTML é processado ou quando um usuário clica em um link). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 271 Gravação de script de contêiner HTML O exemplo a seguir estende a classe HTMLHost para apresentar comportamento normal quando o método window.open() de JavaScript for chamado. O exemplo a seguir define uma subclasse do HTMLLoader que usa a classe personalizada de implementação HTMLHost: package { import flash.html.HTMLLoader; public class MyHTMLHost extends HTMLHost { public function MyHTMLHost() { super(false); } override public function createWindow(opts:HTMLWindowCreateOptions):void { var initOptions:NativeWindowInitOptions = new NativeWindowInitOptions(); var bounds:Rectangle = new Rectangle(opts.x, opts.y, opts.width, opts.height); var html:HTMLLoader = HTMLLoader.createRootWindow(true, initOptions, opts.scrollBarsVisible, bounds); html.stage.nativeWindow.orderToFront(); return html } } O seguinte define uma subclasse da classe HTMLLoader que atribui um objeto MyHTMLHost à respectiva propriedade htmlHost: package { import flash.html.HTMLLoader; import MyHTMLHost; import HTMLLoader; public class MyHTML extends HTMLLoader { public function MyHTML() { super(); htmlHost = new MyHTMLHost(); } } } Para obter detalhes sobre a classe HTMLHost e o método HTMLLoader.createRootWindow() usado nesse exemplo, consulte “Definição de interfaces do usuário como navegadores para conteúdo HTML” na página 263. 272 Capítulo 24: Adição de conteúdo em PDF Aplicativos em execução no Adobe® AIR™ podem produzir não só conteúdo SWF e HTML, mas também em PDF. Aplicativos AIR processam aplicativos em PDF usando a classe HTMLLoader, o mecanismo WebKit e o plug-in para navegador Adobe® Reader®. Em um aplicativo AIR, o conteúdo em PDF pode alongar-se pela atura e largura inteiras de seu aplicativo ou, como alternativa, como uma parte da interface. O plug-in para navegador do Adobe Reader controla a exibição de arquivos em PDF em um aplicativo AIR, portanto, modificações na interface da barra de ferramentas do Reader (como as relacionadas à posição, ancoragem e visibilidade) persistem na visualização subseqüente de arquivos em PDF tanto nos aplicativos AIR como no navegador. Importante: Para processar conteúdo em PDF no AIR, o usuário deve ter o Adobe Reader ou Adobe® Acrobat® versão 8.1 ou posterior instalada. Detecção de recurso de PDF Se o usuário não tiver uma versão instalada do Adobe Reader ou do Adobe Acrobat 8.1 ou posterior, o conteúdo PDF não será exibido no aplicativo AIR. Para detectar se o usuário pode processar conteúdo em PDF, verifique primeiramente a propriedade HTMLLoader.pdfCapability. Essa propriedade está definida como uma das seguintes constantes da classe HTMLPDFCapability: Constante Descrição HTMLPDFCapability.STATUS_OK Uma versão suficiente (8.1 ou posterior) do Adobe Reader é detectada e o conteúdo em PDF pode ser carregado em um objeto HTMLLoader. HTMLPDFCapability.ERROR_INSTALLED_READER_NOT_FOUND Não foi detectada nenhuma versão do Adobe Reader. Um objeto HTMLLoader não pode exibir conteúdo em PDF. HTMLPDFCapability.ERROR_INSTALLED_READER_TOO_OLD O Adobe Reader foi detectado, mas a versão é muito antiga. Um objeto HTMLLoader não pode exibir conteúdo em PDF. HTMLPDFCapability.ERROR_PREFERRED_READER_TOO_OLD Uma versão suficiente (8.1 ou posterior) do Adobe Reader foi detectada, mas a versão do aplicativo configurada para lidar com conteúdo em PDF é anterior ao Reader 8.1. Um objeto HTMLLoader não pode exibir conteúdo em PDF. No Windows, se o Adobe Acrobat ou o Acrobat Reader versão 7.x ou posterior estiver em execução no sistema do usuário, essa versão será usada, mesmo se houver instalada uma versão posterior que ofereça suporte a PDF carregado. Nesse caso, se o valor da propriedade pdfCampability for HTMLPDFCapability.STATUS_OK, quando um aplicativo AIR tentar carregar o conteúdo em PDF, a versão antiga do Acrobat ou do Reader exibirá um alerta (e nenhuma exceção será lançada no aplicativo AIR). Se isso for uma possibilidade para os usuários finais, considere fornecer a eles instruções sobre como fechar o Acrobat enquanto o aplicativo é executado. Pode ser conveniente exibir essas instruções se o conteúdo em PDF não for carregado em um intervalo de tempo aceitável. No Linux, o AIR procura o Adobe Reader no CAMINHO exportado pelo usuário (se ele contiver o comando acroread) e no diretório /opt/Adobe/Reader. O código seguinte detecta se o usuário pode exibir conteúdo em PDF em um aplicativo AIR, e, caso não possa, rastreia o código de erro que corresponde ao objeto de erro HTMLPDFCapability: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 273 Adição de conteúdo em PDF if(HTMLLoader.pdfCapability == HTMLPDFCapability.STATUS_OK) { trace("PDF content can be displayed"); } else { trace("PDF cannot be displayed. Error code:", HTMLLoader.pdfCapability); } Carregamento de conteúdo em PDF Você pode adicionar um PDF a um aplicativo AIR criando uma ocorrência HTMLLoader, definindo as dimensões e carregando o caminho de um PDF. O exemplo a seguir carrega um PDF de um site externo. Substitua a URLRequest com o caminho para um PDF externo disponível. var request:URLRequest = new URLRequest("http://www.example.com/test.pdf"); pdf = new HTMLLoader(); pdf.height = 800; pdf.width = 600; pdf.load(request); container.addChild(pdf); Você também pode carregar conteúdo de URLs de arquivos e esquemas de URL específicos do AIR, como app e appstorage. Por exemplo, o código seguinte carrega o arquivo test.pdf no subdiretório PDFs do diretório do aplicativo: app:/js_api_reference.pdf Para obter mais informações sobre esquemas de URL do AIR, consulte “Uso de esquemas de URL do AIR em URLs” na página 306. Gravando em script o conteúdo em PDF Você pode usar o JavaScript para controlar o conteúdo em PDF, do mesmo modo que em um página da Web no navegador. As extensões JavaScript para o Acrobat oferecem alguns recursos, entre eles: • Controle de ampliação e navegação de página • Processamento de formulários no documento • Controle de eventos multimídia Detalhes completos sobre extensões JavaScript para o Adobe Acrobat são fornecidos na Conexão de desenvolvedores do Adobe Acrobat, em http://www.adobe.com/devnet/acrobat/javascript.html. Noções básicas de comunicação HTML-PDF O JavaScript em uma página HTML pode enviar uma mensagem para o JavaScript no conteúdo em PDF, chamando o método postMessage() do objeto DOM representando o conteúdo em PDF. Por exemplo, considere o seguinte conteúdo em PDF incorporado: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 274 Adição de conteúdo em PDF <object id="PDFObj" data="test.pdf" type="application/pdf" width="100%" height="100%"/> o código JavaScript seguinte, no conteúdo HTML contido envia uma mensagem para o JavaScript no arquivo em PDF: pdfObject = document.getElementById("PDFObj"); pdfObject.postMessage(["testMsg", "hello"]); O arquivo em PDF pode incluirJavaScript para receber essa mensagem. Você pode adicionar o código JavaScript a arquivos em PDF em alguns contextos, incluindo os contextos em nível de documento, pasta, página, campo e lote. Apenas o contexto em nível de documento, que define scripts que são avaliados quando o documento em PDF é aberto, é discutido aqui. Um arquivo em PDF pode adicionar uma propriedade messageHandler ao objeto hostContainer. A propriedade messageHandler é um objeto que define funções do manipulador para responder a mensagens. Por exemplo, o código seguinte define a função para tratar mensagens recebidas pelo arquivo em PDF a partir do contêiner host (que é o conteúdo HTML incorporando o arquivo em PDF): this.hostContainer.messageHandler = {onMessage: myOnMessage}; function myOnMessage(aMessage) { if(aMessage[0] == "testMsg") { app.alert("Test message: " + aMessage[1]); } else { app.alert("Error"); } } O código JavaScript na página HTML pode chamar o método postMessage() do objeto PDF contido na página. Chamar esse método envia uma mensagem ("Hello from HTML") para o JavaScript em nível de documento no arquivo em PDF: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 275 Adição de conteúdo em PDF <html> <head> <title>PDF Test</title> <script> function init() { pdfObject = document.getElementById("PDFObj"); try { pdfObject.postMessage(["alert", "Hello from HTML"]); } catch (e) { alert( "Error: \n name = " + e.name + "\n message = " + e.message ); } } </script> </head> <body onload='init()'> <object id="PDFObj" data="test.pdf" type="application/pdf" width="100%" height="100%"/> </body> </html> Para obter um exemplo mais avançado e obter informações sobre como usar o Acrobat 8 para adicionar JavaScript a um arquivo em PDF, consulte Conteúdo em PDF entre scripts no Adobe AIR. Gravação em script de conteúdo em PDF do ActionScript O código do ActionScript (no conteúdo SWF) não pode se comunicar diretamente com o JavaScript no conteúdo em PDF. Entretanto, o ActionScript pode se comunicar com o JavaScript na página HTML carregada em um objeto HTMLLoader que carrega conteúdo em PDF, e o código JavaScript pode se comunicar com o JavaScript no arquivo em PDF carregado. Para obter mais informações, consulte “Programação em HTML e JavaScript” na página 233. Limitações conhecidas do conteúdo em PDF no AIR O conteúdo em PDF no Adobe AIR tem as seguintes limitações: • O conteúdo em PDF não é exibido em uma janela (um objeto NativeWindow) que seja transparente (na qual a propriedade transparent esteja definida como true). • A ordem de exibição de um arquivo em PDF funciona de forma diferente de outros objetos de exibição em um aplicativo AIR. Embora o conteúdo em PDF se afixe corretamente de acordo com a ordem de exibição de HTML, ele sempre ficará por cima do conteúdo na ordem de exibição do aplicativo AIR. • O conteúdo em PDF não é exibido em uma janela que esteja no modo tela cheia (quando a propriedade displayState do Palco está definida como StageDisplayState.FULL_SCREEN ou StageDisplayState.FULL_SCREEN_INTERACTIVE). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 276 Adição de conteúdo em PDF • Se determinadas propriedades visuais de um objeto HTMLLoader que contenha um documento PDF forem alteradas, o documento PDF se tornará invisível. Essas propriedades incluem filters, alpha, rotation e scaling. Alterá-las torna o arquivo PDF invisível até a redefinição das propriedades. Isso também vale se você alterar essas propriedades de contêineres de objeto de exibição que contêm o objeto HTMLLoader. • O conteúdo PDF fica visível somente quando a propriedade scaleMode do objeto Stage do objeto NativeWindow contendo o conteúdo PDF é definida como StageScaleMode.NO_SCALE. Quando ela é definida com outro valor, o conteúdo PDF não fica visível. • Clicar em links para conteúdo dentro do arquivo em PDF atualiza a posição de rolagem do conteúdo em PDF. Clicar em links para conteúdo fora do arquivo em PDF redireciona o objeto HTMLLoader que contém o PDF (mesmo que o destino de um link seja uma nova janela). • Fluxos de trabalho de comentário de PDF não funcionam no AIR. 277 Capítulo 25: Utilização de gerenciamento de direitos digitais O FMRMS (Servidor de gerenciamento de direitos do Adobe® Flash® Media) fornece aos editores de mídia a capacidade de distribuir conteúdo, especificamente arquivos FLV e MP4, e recuperar custos de produção por meio de compensação direta (paga pelo usuário) ou indireta (paga por propaganda) por seus consumidores. Os editores distribuem mídia como FLVs criptografados que podem ser baixados e reproduzidos no Adobe® Media Player™ ou em qualquer aplicativo do AIR que use a API de DRM (gerenciamento de direitos digitais). Com o FMRMS, os provedores de conteúdo podem usar licenciamento baseado em identidade para proteger seu conteúdo com credenciais de usuários. Por exemplo, um consumidor deseja exibir um programa de televisão, mas não deseja assistir às propagandas que o acompanham. Para evitar assistir às propagandas, o consumidor registra e paga ao editor de conteúdo um prêmio. O usuário pode usar sua credencial de autenticação para obter acesso e assistir ao programa sem os comerciais. Outro consumidor pode querer exibir o conteúdo offline ao viajar sem acesso à Internet. Após se registrar e pagar ao editor de conteúdo pelo serviço premium, a credencial de autenticação do usuário permite a eles acessarem e baixarem o programa do site do editor. O usuário pode então exibir o conteúdo offline durante o período permitido. O conteúdo também é protegido pelas credenciais do usuário e não pode ser compartilhado com outros usuários. Quando um usuário tenta reproduzir um arquivo criptografado por DRM, o aplicativo entra em contato com o FMRMS que, por sua vez, entra em contato com o sistema do editor de conteúdo por sua SPI (interface de provedor de serviços) para autenticar o usuário e recuperar a licença, um comprovante que determina se o usuário pode acessar o conteúdo e, se sim, por quanto tempo. O comprovante também determina se o usuário pode acessar o conteúdo offline e, se sim, por quanto tempo. Como tal, as credenciais do usuário são necessárias para determinar o acesso ao conteúdo criptografado. O licenciamento baseado em identidade também suporta o acesso anônimo. Por exemplo, o acesso anônimo pode ser usado pelo provedor para distribuir conteúdo suportado por propaganda ou para permitir acesso livre ao conteúdo atual por um número de dias especificado. O material de arquivo pode ser considerado conteúdo premium que deve ser pago e requer credenciais do usuário. O provedor de conteúdo também pode especificar e restringir o tipo e a versão do player necessário para seu conteúdo. É descrito aqui como habilitar seu aplicativo do AIR para reproduzir conteúdo protegido com criptografia de gerenciamento de direitos digitais. Não é necessário entender como criptografar conteúdo usando DRM, mas supõese que você tenha acesso a conteúdo criptografado por DRM e esteja se comunicando com o FMRMS para autenticar o usuário e recuperar o comprovante. Para uma visão geral do FMRMS, incluindo a criação de diretivas, consulte a documentação incluída com o FMRMS. Para obter informações sobre o Adobe Media Player, consulte a Ajuda do Adobe Media Player disponível no Adobe Media Player. Informações online adicionais sobre o gerenciamento de direitos digitais Você pode encontrar mais informações sobre o gerenciamento de direitos digitais nestas fontes: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 278 Utilização de gerenciamento de direitos digitais Referência de Linguagem • AuthenticationMethod • DRMAuthenticationCompleteEvent • DRMAuthenticationErrorEvent • DRMAuthenticateEvent • DRMContentData • DRMErrorEvent • DRMManager • DRMPlaybackTimeWindow • DRMStatusEvent • DRMVoucher • LoadVoucherSetting • NetStream Artigos e amostras do Adobe Developer Connection • Conexão de desenvolvedores do Adobe AIR para Flash (procure "gerenciamento de direitos digitais" ou "drm") Compreensão do fluxo de trabalho FLV criptografado Existem quatro tipos de eventos: StatusEvent, DRMAuthenticateEvent, DRMErrorEvent e DRMStatusEvent, que podem ser despachados quando um aplicativo do AIR tenta reproduzir um arquivo criptografado por DRM. Para suportar esses arquivos, o aplicativo deve adicionar ouvintes de eventos para manipular os eventos DRM. A seguir, está o fluxo de trabalho de como o aplicativo do AIR pode recuperar e reproduzir o conteúdo protegido com criptografia DRM: 1 O aplicativo, usando um objeto NetStream, tenta reproduzir um arquivo FLV ou MP4. Se o conteúdo for criptografado, um evento events.StatusEvent é despachado com o código, DRM.encryptedFLV, indicando que o FLV está criptografado. Nota: Se um aplicativo não quiser reproduzir o arquivo criptografado por DRM, ele poderá ouvir o evento de status despachado quando encontrar um conteúdo criptografado e, em seguida, permitir que o usuário saiba que o arquivo não é suportado e fechar a conexão. 2 Se o arquivo for criptografado de modo anônimo, o que significa que todos os usuários podem exibir o conteúdo sem inserir credenciais de autenticação, o aplicativo do AIR continuará com a última etapa desse fluxo de trabalho. No entanto, se o arquivo exigir uma licença baseada em identidade, o que significa que a credencial do usuário é exigida, o objeto NetStream despachará um objeto DRMAuthenticateEvent. O usuário deve fornecer suas credenciais de autenticação antes que a reprodução seja iniciada. 3 O aplicativo do AIR deve fornecer algum mecanismo para coletar as credenciais de autenticação necessárias. As propriedades usernamePrompt, passwordPrompt e urlPrompt da classe DRMAuthenticationEvent, fornecidas pelo servidor de conteúdo, podem ser usadas para instruir o usuário final com informações sobre os dados necessários. Você pode usar essas propriedades de construir uma interface de usuário para recuperar as credenciais de usuário necessárias. Por exemplo, a seqüência de caracteres de valor usernamePrompt pode afirmar que o nome de usuário deve estar na forma de um endereço de e-mail. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 279 Utilização de gerenciamento de direitos digitais Nota: O AIR não fornece uma interface de usuário padrão para coletar credenciais de autenticação. O desenvolvedor do aplicativo deve escrever a interface de usuário e manipular os eventos DRMAuthenticateEvent. Se o aplicativo não fornecer um ouvinte de eventos para objetos DRMAuthenticateEvent, o objeto criptografado por DRM permanecerá em um estado “aguardando credenciais” e o conteúdo não está, portanto, disponível. 4 Depois que o aplicativo obtiver as credenciais do usuário, ele as transmitirá com o método setDRMAuthenticationCredentials() ao objeto NetStream. Isso sinaliza ao objeto NetStream que ele deve tentar autenticar o usuário na próxima oportunidade disponível. O AIR então transmite a credencial ao FMRMS para autenticação. Se o usuário foi autenticado, o aplicativo continuará com a etapa seguinte. Se a autenticação falhar, o objeto NetStream despachará um novo objeto DRMAuthenticateEvent e o aplicativo retornará à etapa 3. Esse processo é repetido indefinidamente. O aplicativo deve fornecer um mecanismo para manipular e limitar as tentativas de autenticação repetidas. Por exemplo, o aplicativo poderia permitir ao usuário cancelar a tentativa que pode fechar a conexão do NetStream. 5 Depois que o usuário estiver autenticado, ou se a criptografia anônima for usada, o subsistema DRM recupera o comprovante. O comprovante é usado para verificar se o usuário está autorizado a exibir o conteúdo. As informações no comprovante podem ser aplicadas aos usuários autenticados e anônimos. Por exemplo, os usuários autenticados e anônimos podem ter acesso ao conteúdo por um período de tempo especificado antes que o conteúdo expire ou podem não ter acesso ao conteúdo porque o provedor de conteúdo pode não suportar a versão do aplicativo de exibição. Se não tiver ocorrido nenhum erro e o usuário foi autorizado com êxito a exibir o conteúdo, o objeto NetStream despachará um objeto DRMStatusEvent e o aplicativo do AIR começará a reprodução. O objeto DRMStatusEvent guarda as informações do comprovante relacionadas, que identifica a diretiva e as permissões do usuário. Por exemplo, ele contém informações com relação a se o conteúdo pode ser disponibilizado offline ou quando o comprovante expira e o conteúdo não pode mais se exibido. O aplicativo pode usar esses dados para informar ao usuário sobre o status de sua diretiva. Por exemplo, o aplicativo pode exibir o número de dias restantes que o usuário possui para exibir o conteúdo em uma barra de status. Se ao usuário for permitido acesso offline, o comprovante será armazenado em cache e o conteúdo criptografado será baixado na máquina do usuário e estará acessível pela duração definida no período offline. A propriedade detail no evento contém "DRM.voucherObtained". O aplicativo decide onde armazenar o conteúdo localmente para que ele esteja disponível off-line. No AIR 1.5, você também pode pré-carregar comprovantes usando a classe DRMManager. Todos os erros relacionados a DRM resultam em o aplicativo despachar um objeto de evento DRMErrorEvent. O AIR manipula as falhas de autenticação encontradas usando o método setDRMAuthenticationCredentials()do NetStream, despachando novamente o objeto DRMAuthenticationEvent. Todos os outros eventos de erro devem ser explicitamente manipulados pelo aplicativo. Isso inclui casos nos quais o usuário insere credenciais válidas, mas o comprovante que protege o conteúdo criptografado restringe o acesso ao conteúdo. Por exemplo, um usuário autenticado pode ainda não ter acesso ao conteúdo porque os direitos não foram pagos. Isso poderia ocorrer também onde dois usuários, ambos membros registrados com o mesmo editor de mídia, estão tentando compartilhar conteúdo pelo qual apenas um dos membros pagou. O aplicativo deve informar o usuário sobre o erro, como as restrições para o conteúdo, bem como fornecer uma alternativa, como instruções sobre como registrar e pagar pelos direitos para exibir o conteúdo. Pré-carregar comprovantes para reprodução offline Você pode pré-carregar os comprovantes necessários para reproduzir conteúdo protegido por DRM. Comprovantes pré-carregados permitem que os usuários vejam o conteúdo com ou sem conexão à Internet. (O processo de précarregamento propriamente dito obviamente requer conexão com Internet.) Use o método preloadEmbeddedMetadata() da classe NetStream e a classe 1.5 DRMManager do AIR 1.5 para pré-carregar comprovantes. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 280 Utilização de gerenciamento de direitos digitais As etapas a seguir descrevem o fluxo de trabalho para pré-carregar o comprovante de um arquivo de mídia protegido por DRM: 1 Baixe e armazene o arquivo de mídia. (Metadados DRM só podem ser pré-carregados de arquivos armazenados localmente.) 2 Crie os objetos NetConnection e NetStream, fornecendo implementações para as funções de retorno de chamada onDRMContentData() e onPlayStatus() do objeto cliente NetStream. 3 Crie um objeto NetStreamPlayOptions e defina a propriedade stream para a URL do arquivo de mídia local. 4 Chame o NetStream preloadEmbeddedMetadata(), passando no objeto NetStreamPlayOptions que identifica o arquivo de mídia que será analisado. 5 Se o arquivo de mídia contiver metadados DRM, a função de retorno de chamada onDRMContentData() será chamada. Os metadados são transmitidos a essa função como objeto DRMContentData. 6 Use o objeto DRMContentData para obter o comprovante usando o método loadVoucher() do DRMManager. Se o valor da propriedade authenticationMethod do objeto DRMContentData for userNameAndPassword, você deverá autenticar o usuário no servidor de direitos de mídia antes de carregar o comprovante. As propriedades serverURL e domain do objeto DRMContentData podem ser passadas para o método authenticate() do DRMManager, juntamente com as credenciais do usuário. 7 A função de retorno de chamada onPlayStatus() é chamada após a conclusão da análise do arquivo. Se a função onDRMContentData() não tiver sido chamada, o arquivo não conterá os metadados necessários para obter um comprovante (e pode não estar protegido por DRM). O exemplo de código a seguir ilustra como pré-carregar um comprovante DRM para um arquivo de mídia local: package { import flash.display.Sprite; import flash.events.DRMAuthenticationCompleteEvent; import flash.events.DRMAuthenticationErrorEvent; import flash.events.DRMErrorEvent; import flash.ev ents.DRMStatusEvent; import flash.events.NetStatusEvent; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.NetStreamPlayOptions; import flash.net.drm.AuthenticationMethod; import flash.net.drm.DRMContentData; import flash.net.drm.DRMManager; import flash.net.drm.LoadVoucherSetting; public class DRMPreloader extends Sprite { private var videoURL:String = "app-storage:/video.flv"; private var userName:String = "user"; private var password:String = "password"; private var preloadConnection:NetConnection; private var preloadStream:NetStream; private var drmManager:DRMManager = DRMManager.getDRMManager(); private var drmContentData:DRMContentData; public function DRMPreloader():void { drmManager.addEventListener( DRMAuthenticationCompleteEvent.AUTHENTICATION_COMPLETE, onAuthenticationComplete ); drmManager.addEventListener( DRMAuthenticationErrorEvent.AUTHENTICATION_ERROR,onAuthenticationError ); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 281 Utilização de gerenciamento de direitos digitais drmManager.addEventListener(DRMStatusEvent.DRM_STATUS, onDRMStatus); drmManager.addEventListener(DRMErrorEvent.DRM_ERROR, onDRMError); preloadConnection = new NetConnection(); preloadConnection.addEventListener(NetStatusEvent.NET_STATUS, onConnect); preloadConnection.connect(null); } private function onConnect( event:NetStatusEvent ):void { preloadMetadata(); } private function preloadMetadata():void { preloadStream = new NetStream( preloadConnection ); preloadStream.client = this; var options:NetStreamPlayOptions = new NetStreamPlayOptions(); options.streamName = videoURL; preloadStream.preloadEmbeddedData( options ); } public function onDRMContentData( drmMetadata:DRMContentData ):void { drmContentData = drmMetadata; if ( drmMetadata.authenticationMethod == AuthenticationMethod.USERNAME_AND_PASSWORD ) { authenticateUser(); } else { getVoucher(); } } private function getVoucher():void { drmManager.loadVoucher( drmContentData, LoadVoucherSetting.ALLOW_SERVER ); } private function authenticateUser():void { drmManager.authenticate( drmContentData.serverURL, drmContentData.domain, userName, password ); } private function onAuthenticationError( event:DRMAuthenticationErrorEvent ):void { trace( "Authentication error: " + event.errorID + ", " + event.subErrorID ); } private function onAuthenticationComplete( event:DRMAuthenticationCompleteEvent ):void { DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 282 Utilização de gerenciamento de direitos digitais trace( "Authenticated to: " + event.serverURL + ", domain: " + event.domain ); getVoucher(); } private function onDRMStatus( event:DRMStatusEvent ):void { trace( "DRM Status: " + event.detail); trace("--Voucher allows offline playback = " + event.isAvailableOffline ); trace("--Voucher already cached = " + event.isLocal ); trace("--Voucher required authentication = " + !event.isAnonymous ); } private function onDRMError( event:DRMErrorEvent ):void { trace( "DRM error event: " + event.errorID + ", " + event.subErrorID + ", " + event.text ); } public function onPlayStatus( info:Object ):void { preloadStream.close(); } } } Membros e eventos relacionados a DRM da classe NetStream A classe NetStream fornece uma conexão de streaming unidirecional entre o Flash Player ou um aplicativo do AIR e o Flash Media Server ou o sistema de arquivos local. (A classe NetStream também suporta o download progressivo.) Um objeto NetStream é um canal em um objeto NetConnection. Em um aplicativo AIR, a classe NetStream despacha quatro eventos relacionados a DRM: Evento Descrição drmAuthenticate Definido na classe DRMAuthenticateEvent, esse evento é despachado quando um objeto NetStream tenta reproduzir conteúdo criptografado por DRM que exija uma credencial de usuário para a autenticação antes da reprodução. As propriedades desse evento incluem as propriedades header, usernamePrompt, passwordPrompt e urlPrompt que podem ser usadas para obter e definir as credenciais do usuário. Esse evento ocorre repetidamente até que o objeto NetStream receba credenciais de usuário válidas. drmError Definido na classe DRMErrorEvent e despachado quando um objeto NetStream encontra um erro relacionado ao DRM ao tentar reproduzir um arquivo criptografado por DRM. Por exemplo, um objeto de evento de erro DRM é despachado quando a autorização do usuário falha. Talvez seja porque o usuário não adquiriu os direitos de visualização do conteúdo ou porque o provedor de conteúdo não oferece suporte ao aplicativo de visualização. drmStatus Definido na classe DRMStatusEvent, é despachado quando o conteúdo criptografado por DRM inicia a reprodução (quando o usuário for autenticado e autorizado a reproduzir o conteúdo). O objeto DRMStatusEvent contém informações relacionadas ao comprovante, tais como se o conteúdo pode ser disponibilizado offline ou quando o comprovante vencerá e o conteúdo não poderá mais ser visualizado. status Definido em events.StatusEvent e apenas despachado quando o aplicativo tenta reproduzir o conteúdo criptografado com DRM, invocando o método NetStream.play(). O valor da propriedade do código de status será "DRM.encryptedFLV". A classe NetStream inclui os seguintes métodos específicos de DRM: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 283 Utilização de gerenciamento de direitos digitais Método Descrição resetDRMVouchers() Exclui todos os dados de comprovação de gerenciamento de direitos digitais armazenados localmente em cache. O aplicativo deve baixar o comprovante novamente para que o usuário possa acessar o conteúdo criptografado. Por exemplo, o código a seguir remove todos os comprovantes do cache: NetStream.resetDRMVouchers(); setDRMAuthenticationCredentials() Transmite um conjunto de credenciais de autenticação, a saber, nome de usuário, senha e tipo de autenticação, ao objeto NetStream para autenticação. Os tipos de autenticação válidos são "drm" e "proxy" . Com o tipo de autenticação "drm" , as credenciais fornecidas são autenticadas em relação ao FMRMS. Com o tipo de autenticação "proxy", as credenciais são autenticadas em comparação ao servidor proxy e devem ser compatíveis àquelas solicitadas por ele. Por exemplo, a opção "proxy" permite que o aplicativo autentique em comparação a um servidor proxy se uma empresa solicitar essa etapa antes que o usuário possa acessar a Internet. A menos que seja usada a autenticação anônima, depois da autenticação proxy, o usuário ainda precisará ser autenticado comparando ao FMRMS para obter o comprovante e reproduzir o conteúdo. Você pode usar setDRMAuthenticationcredentials() uma segunda vez, com a opção "drm" para autenticar em comparação ao FMRMS. preloadEmbeddedMetadata() Analisa se um arquivo de mídia local contém metadados incorporados. Quando metadados relacionados a DRM são encontrados, o AIR chama a função de retorno de chamada onDRMContentData() . Além disso, um objeto NetStream chama as funções de retorno de chamada onDRMContentData() e onPlayStatus() como resultado de uma chamada para o método preloadEmbeddedMetaData(). A função onDRMContentData() é chamada quando os metadados DRM são encontrados em um arquivo de mídia. A função onPlayStatus() é chamada quando o arquivo é totalmente analisado. As funções onDRMContentData() e onPlayStatus() devem ser definidas no objeto client atribuído à ocorrência do NetStream. Se você usar o mesmo objeto NetStream para précarregar comprovantes e reproduzir conteúdo, deverá aguardar pela chamada onPlayStatus() gerada pelo preloadEmbeddedMetaData() antes de iniciar a reprodução. No seguinte código, nome de usuário (“administrator”), senha (“password”) e o tipo de autenticação “drm” são definidos para autenticar o usuário. O método setDRMAuthenticationCredentials() deve fornecer credenciais correspondentes a credenciais conhecidas e aceitas pelo provedor de conteúdo (as mesmas credenciais de usuário que forneciam permissão para exibir o conteúdo). O código para reproduzir o vídeo e certificar-se de que foi feita uma conexão bem-sucedida ao streaming de vídeo não está incluída aqui. var connection:NetConnection = new NetConnection(); connection.connect(null); var videoStream:NetStream = new NetStream(connection); videoStream.addEventListener(DRMAuthenticateEvent.DRM_AUTHENTICATE, drmAuthenticateEventHandler) private function drmAuthenticateEventHandler(event:DRMAuthenticateEvent):void { videoStream.setDRMAuthenticationCredentials("administrator", "password", "drm"); } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 284 Utilização de gerenciamento de direitos digitais Uso da classe DRMStatusEvent Um objeto NetStream despacha um objeto DRMStatusEvent quando o conteúdo protegido, que usa DRM, começa a ser reproduzido com êxito (quando o comprovante é verificado e quando o usuário é autenticado e autorizado a exibir o conteúdo). DRMStatusEvent também é despachado para usuários anônimos se for permitido acesso a eles. O comprovante é consultado para verificar se usuários anônimos, que não precisam de autenticação, podem acessar e reproduzir o conteúdo. Pode ser negado o acesso a usuários anônimos por várias razões. Por exemplo, um usuário anônimo pode não ter acesso ao conteúdo porque ele expirou. O objeto DRMStatusEvent contém informações relacionadas ao comprovante, tais como se o conteúdo pode ser disponibilizado offline ou quando o comprovante vencerá e o conteúdo não poderá mais ser visualizado. O aplicativo pode usar esses dados para transmitir suas permissões e o status da diretiva do usuário. Propriedades DRMStatusEvent A classe DRMStatusEvent inclui as seguintes propriedades: Propriedade Descrição contentData Um objeto DRMContentData contendo os metadados DRM incorporados no conteúdo. detail Uma seqüência de caracteres que explica o contexto do evento de status. No DRM 1.0, o único valor válido é DRM.voucherObtained. isAnonymous Indica se o conteúdo, protegido com criptografia por DRM, está disponível sem exigir que um usuário forneça credenciais de autenticação (true) ou não (false). Um valor false significa que os usuários devem fornecer um nome de usuário e uma senha que corresponda aos conhecidos e esperados pelo provedor de conteúdo. isAvailableOffline Indica se o conteúdo, protegido com criptografia por DRM, pode ser disponibilizado offline (true) ou não (false). Para que o conteúdo protegido digitalmente seja disponibilizado offline, seu comprovante deve ser armazenado em cache na máquina local do usuário. isLocal Indica se o comprovante necessário para reproduzir o conteúdo está armazenado em cache localmente. offlineLeasePeriod O número restante de dias que o conteúdo pode ser exibido offline. diretivas Um objeto personalizado que pode conter propriedades DRM personalizadas. comprovante O DRMVoucher. voucherEndDate A data absoluta na qual o comprovante expira e o conteúdo não pode mais ser exibido. Criação de um manipulador DRMStatusEvent O exemplo a seguir cria um manipulador de eventos que fornece as informações de status de conteúdo DRM para o objeto NetStream que originou o evento. Adicione esse manipulador de eventos a um objeto NetStream que aponta para o conteúdo criptografado por DRM. function drmStatusEventHandler(event:DRMStatusEvent):void { trace(event); } function drmStatusEventHandler(event:DRMStatusEvent):void { trace(event); } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 285 Utilização de gerenciamento de direitos digitais Uso da classe DRMAuthenticateEvent O objeto DRMAuthenticateEvent é despachado quando um objeto NetStream tenta reproduzir conteúdo criptografado por DRM que exija uma credencial de usuário para a autenticação antes da reprodução. O manipulador DRMAuthenticateEvent é responsável pela coleta das credenciais necessárias (nome de usuário, senha e tipo) e pela transmissão dos valores ao método NetStream.setDRMAuthenticationCredentials() para validação. Cada aplicativo do AIR deve fornecer algum mecanismo para obter credenciais do usuário. Por exemplo, o aplicativo poderia fornecer um usuário com uma interface de usuário simples para digitar valores de nome de usuário e senha e, opcionalmente, o valor de tipo também. O aplicativo do AIR também deve fornecer um mecanismo para manipular e limitar as tentativas de autenticação repetidas. Propriedades DRMAuthenticateEvent A classe DRMAuthenticateEvent inclui as seguintes propriedades: Propriedade Descrição authenticationType Indica se as credenciais fornecidas são para autenticação em comparação ao FMRMS (“drm”) ou um servidor proxy (“proxy”). Por exemplo, a opção "proxy" permite que o aplicativo autentique em comparação a um servidor proxy se uma empresa solicitar essa etapa antes que o usuário possa acessar a Internet. A menos que seja usada a autenticação anônima, depois da autenticação proxy, o usuário ainda precisará ser autenticado comparando ao FMRMS para obter o comprovante e reproduzir o conteúdo. Você pode usar setDRMAuthenticationcredentials() uma segunda vez, com a opção "drm" para autenticar em comparação ao FMRMS. header O cabeçalho do arquivo de conteúdo criptografado fornecido pelo servidor. Ele contém informações sobre o contexto do conteúdo criptografado. netstream O objeto NetStream que iniciou esse evento. passwordPrompt Um prompt para uma credencial de senha, fornecida pelo servidor. A seqüência de caracteres pode incluir instruções para o tipo de senha necessária. urlPrompt Um prompt para uma seqüência de caracteres de URL, fornecida pelo servidor. A seqüência de caracteres pode fornecer o local para onde o nome de usuário e a senha são enviados. usernamePrompt Um prompt para uma credencial de nome de usuário, fornecida pelo servidor. A seqüência de caracteres pode incluir instruções para o tipo de nome de usuário necessário. Por exemplo, um provedor de conteúdo pode exigir um endereço de e-mail como o nome de usuário. Criação de um manipulador DRMAuthenticateEvent O exemplo a seguir cria um manipulador de eventos que transmite um conjunto de credenciais de autenticação codificadas ao objeto NetStream que originou o evento. (O código para reproduzir o vídeo e certificar-se de que foi feita uma conexão bem-sucedida ao streaming de vídeo não está incluída aqui.) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 286 Utilização de gerenciamento de direitos digitais var connection:NetConnection = new NetConnection(); connection.connect(null); var videoStream:NetStream = new NetStream(connection); videoStream.addEventListener(DRMAuthenticateEvent.DRM_AUTHENTICATE, drmAuthenticateEventHandler) private function drmAuthenticateEventHandler(event:DRMAuthenticateEvent):void { videoStream.setDRMAuthenticationCredentials("administrator", "password", "drm"); } Criação de uma interface para recuperar credenciais do usuário No caso em que o conteúdo DRM requer autenticação do usuário, o aplicativo do AIR normalmente precisa recuperar as credenciais de autenticação do usuário por uma interface de usuário. Uso da classe DRMErrorEvent O AIR despacha um objeto DRMErrorEvent quando um objeto NetStream, tentando reproduzir um arquivo criptografado por DRM, encontra um erro relacionado a DRM. No caso de credenciais de usuário inválidas, o objeto DRMAuthenticateEvent manipula o erro despachando-o repetidamente até que o usuário insira credenciais válidas ou o aplicativo do AIR negue tentativas futuras. O aplicativo deve ouvir qualquer evento de erro do DRM para detectar, identificar e manipular os erros relacionados a DRM. Se um usuário inserir credenciais válidas, ele ainda pode não exibir o conteúdo criptografado, dependendo dos termos do comprovante do DRM. Por exemplo, se o usuário estiver tentando exibir o conteúdo em um aplicativo não autorizado, isto é, um aplicativo não validado pelo editor do conteúdo criptografado. Neste caso, um objeto DRMErrorEvent é despachado. Os eventos de erro também podem ser disparados se o conteúdo estiver corrompido ou se a versão do aplicativo não corresponder ao que é especificado pelo comprovante. O aplicativo deve fornecer um mecanismo apropriado para manipular erros. Propriedades DRMErrorEvent A tabela a seguir lista os erros relatados pelo objeto DRMErrorEvent: Código de erro principal Código de erro secundário Detalhes do erro 1001 não usado Falha na autenticação do usuário. 1002 não usado O FMRMS não suporta SSL (Secure Sockets Layer). 1003 não usado O conteúdo expirou e não está mais disponível para exibição. 1004 não usado Falha na autorização do usuário. Isso pode ocorrer, por exemplo, se o usuário não tiver adquirido o conteúdo e, portanto, não possuir os direitos de exibi-lo. 1005 não usado Server URL Descrição Não é possível conectar ao servidor. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 287 Utilização de gerenciamento de direitos digitais Código de erro principal Código de erro secundário Detalhes do erro 1006 não usado Uma atualização de cliente é necessária, isto é, o FMRMS requer um novo mecanismo DRM. 1007 não usado Falha interna genérica. 1008 Código de erro de descriptografia detalhada Chave de licença incorreta. 1009 não usado O conteúdo FLV está corrompido. 1010 não usado 1011 não usado A versão do aplicativo não corresponde ao que está especificado na diretiva. 1012 não usado Falha na verificação do comprovante associado ao conteúdo criptografado, indicando que o conteúdo pode estar corrompido. 1013 não usado Não foi possível salvar o comprovante associado ao conteúdo criptografado. 1014 não usado Falha na verificação da integridade do cabeçalho FLV, indicando que o conteúdo pode estar corrompido. Código de erro principal ID de erro secundária 3300 Código de erro do servidor de diretivas da Adobe O aplicativo detectou um comprovante inválido associado ao conteúdo. 3301 não usado Falha na autenticação do usuário. 3302 não usado SSL não suportado pelo FMRMS. 3303 não usado O conteúdo expirou e não está mais disponível para exibição. 3304 não usado Falha na autorização do usuário. Isso pode ocorrer mesmo se o usuário estiver autenticado, por exemplo, se o usuário não tiver adquirido os direitos para exibir o conteúdo. 3305 não usado 3306 não usado Uma atualização de cliente é necessária, isto é, o FMRMS requer um novo mecanismo de cliente DRM. 3307 não usado Falha genérica no DRM interno. 3308 Código de erro de descriptografia detalhada Chave de licença incorreta. 3309 não usado O conteúdo de vídeo do Flash está corrompido. publisherID:applicationID Detalhes do erro Server URL Descrição A ID do aplicativo de exibição não corresponde a uma ID válida suportada pelo editor de conteúdo. Descrição Não é possível conectar ao servidor. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 288 Utilização de gerenciamento de direitos digitais Código de erro principal ID de erro secundária Detalhes do erro Descrição 3310 não usado publisherID:applicationID A ID do aplicativo de exibição não corresponde a uma ID válida suportada pelo editor de conteúdo. Em outras palavras, o aplicativo de exibição não é suportado pelo provedor de conteúdo. 3311 não usado mín=x:máx=y A versão do aplicativo não corresponde ao que está especificado no comprovante. 3312 não usado Falha na verificação do comprovante associado ao conteúdo criptografado, indicando que o conteúdo pode estar corrompido. 3313 não usado Não foi possível salvar o comprovante associado ao conteúdo criptografado no Microsafe. 3314 não usado Falha na verificação da integridade do cabeçalho FLV, indicando que o conteúdo pode estar corrompido. 3315 não usado A reprodução remota do conteúdo protegido por DRM não é permitida. 3316 não usado Módulo AdobeCP faltando. 3317 não usado Falha no carregamento do módulo AdobeCP. 3318 não usado Versão incompatível do AdobeCP encontrada. 3319 não usado Ponto de entrada de API do AdobeCP faltando. 3320 não usado Módulo AdobeCP não autenticado. Criação de um manipulador DRMErrorEvent O exemplo a seguir cria um manipulador de eventos para o objeto NetStream que originou o evento. Ele é chamado quando o NetStream encontra um erro ao tentar reproduzir o conteúdo criptografado por DRM. Normalmente, quando um aplicativo encontra um erro, ele executa várias tarefas de limpeza, informa o usuário do erro e fornece opções para resolver o problema. private function drmErrorEventHandler(event:DRMErrorEvent):void { trace(event.toString()); } Uso da classe DRMManager Use a classe DRMManager para gerenciar comprovantes e sessões do servidor de direitos de mídia em um aplicativo AIR. A classe DRMManager está disponível na versão 1.5 ou superior do AIR. Gerenciamento de comprovante DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 289 Utilização de gerenciamento de direitos digitais Sempre que um usuário reproduz um arquivo de mídia protegido por DRM, o AIR obtém e armazena em cache o comprovante da licença necessário para exibir o conteúdo. Se o aplicativo salvar o arquivo localmente e o comprovante permitir a reprodução offline, o usuário poderá exibir o conteúdo mesmo se não houver conexão ao servidor de direitos de mídia disponível. Usando o DRMManager e o método preloadEmbeddedMetadata() do NetStream, você pode pré-armazenar o comprovante em cache, de forma que o aplicativo não precise iniciar a reprodução para obter a licença necessária para exibir o conteúdo. Por exemplo, seu aplicativo pode baixar o arquivo de mídia e obter o comprovante enquanto o usuário ainda está online. Para pré-carregar um comprovante, use o método preloadEmbeddedMetadata() do NetStream para obter um conteúdo do objeto DRMContentData. O objeto DRMContentData contém a URL e o domínio do servidor dos direitos de mídia que pode fornecer a licença e descreve se a autenticação é necessária. Com essas informações, você pode chamar o método loadVoucher() do DRMManager para obter o comprovante e armazená-lo em cache. O fluxo de trabalho para pré-carregar comprovantes é descrito com mais detalhes em “Pré-carregar comprovantes para reprodução offline” na página 279. Gerenciamento de sessão Você também pode usar o DRMManager para autenticar o usuário para um servidor de direitos de mídia e gerenciar sessões persistentes. Chame o método authenticate() do DRMManager para estabelecer uma sessão com o servidor de direitos de mídia. Quando a autenticação for concluída com êxito, o DRMManager despachará um objeto DRMAuthenticationCompleteEvent. Esse objeto contém um token de sessão. Você pode salvar esse token para estabelecer sessões futuras, de forma que o usuário não precise fornecer suas credenciais de conta. Envie o token para o método setAuthenticationToken() a fim de estabelecer uma nova sessão autenticada. (A expiração de token e outros atributos são determinados pelas configurações do servidor que o gera. A estrutura de dados do token não deve ser interpretada pelo código do aplicativo do AIR e pode ser alterada em atualizações futuras do AIR). É possível transferir tokens de autenticação para outros computadores. Para proteger os tokens, armazene-os no depósito local criptografado do AIR. Consulte “Armazenamento de dados criptografados” na página 215 para obter mais informações. Eventos do DRMStatus O DRMManager despacha um objeto DRMStatusEvent após uma chamada bem-sucedida para o método loadVoucher(). Se um comprovante for obtido, a propriedade de detalhes do objeto do evento terá o valor: "DRM.voucherObtained", e a propriedade voucher conterá o objeto DRMVoucher. Se um comprovante não for obtido, a propriedade detail ainda terá o valor: "DRM.voucherObtained"; no entanto, a propriedade voucher será null. Você pode deixar de obter um comprovante se, por exemplo, usar LoadVoucherSetting de localOnly e não existir um comprovante armazenado em cache localmente. Se a chamada loadVoucher() não for concluída com êxito, talvez por causa de um erro de autenticação ou comunicação, o DRMManager despachará um objeto DRMErrorEvent em vez disso. Eventos DRMAuthenticationComplete O DRMManager despacha um objeto DRMAuthenticationCompleteEvent quando um usuário é autenticado com êxito por meio de uma chamada para o método authenticate(). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 290 Utilização de gerenciamento de direitos digitais No AIR 1.5, o objeto DRMAuthenticationCompleteEvent contém um token reutilizável que pode ser usado para persistir em autenticações do usuário em sessões do aplicativo. Passe esse token para o método setAuthenticationToken() do DRMManager, a fim de estabelecer novamente a sessão. (Atributos de token, como expiração, são definidos pelo criador do token. O AIR não fornece uma API para a examinar atributos de token). Eventos DRMAuthenticationError O DRMManager despacha um objeto DRMAuthenticationErrorEvent quando um usuário não pode ser autenticado com êxito por meio de uma chamada para os métodos authenticate() ou setAuthenticationToken(). Uso da classe DRMContentData O objeto DRMContentData contém as propriedades de metadados de um arquivo de mídia protegido por DRM. As propriedades DRMContentData contêm as informações necessárias para obter um comprovante de licença para exibir o conteúdo. 291 Capítulo 26: Inicialização do aplicativo e opções de saída Esta seção discute opções e considerações para inicializar um aplicativo instalado do Adobe® AIR™, bem como opções e considerações para fechar um aplicativo em execução. Invocação do aplicativo Um aplicativo do AIR é invocado quando o usuário (ou o sistema operacional): • Inicia o aplicativo do shell da área de trabalho. • Usa o aplicativo como um comando em um shell de linha de comando. • Abre um tipo de arquivo para o qual o aplicativo é o aplicativo de abertura padrão. • (Mac OS X) clica no ícone do aplicativo na barra de tarefas do encaixe (esteja o aplicativo em execução ou não no momento). • Opta por inicializar o aplicativo do instalador (na extremidade de um novo processo de instalação ou após clicar duas vezes no arquivo do AIR para um aplicativo já instalado). • Começa uma atualização de um aplicativo do AIR quando a versão instalada tiver assinalado que está lidando sozinha com atualizações do aplicativo (incluindo uma declaração <customUpdateUI>true</customUpdateUI> no arquivo do descritor do aplicativo). • Visita uma página da Web que hospeda um crachá ou aplicativo do Flash que chama o método com.adobe.air.AIR launchApplication() especificando as informações de identificação para o aplicativo do AIR. (O descritor do aplicativo deve incluir também uma declaração <allowBrowserInvocation>true</allowBrowserInvocation> para que a invocação do navegador seja bemsucedida.) Consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. Sempre que um aplicativo do AIR for invocado, o AIR despacha um objeto de tipo InvokeEvent invoke pelo objeto singleton NativeApplication. Para permitir que o tempo de um aplicativo se inicialize e registre um ouvinte de evento, eventos invoke são enfileirados em vez de descartados. Assim que um ouvinte é registrado, todos os eventos enfileirados são entregues. Nota: Quando um aplicativo é invocado usando o recurso de invocação do navegador, o objeto NativeApplication despacha apenas um evento invoke se o aplicativo ainda não estiver em execução. Consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. Para receber eventos invoke, chame o método addEventListener() do objeto NativeApplication (NativeApplication.nativeApplication). Quando um ouvinte de evento registra um evento invoke, ele também recebe todos os eventos invoke que ocorreram antes do registro. Eventos invoke enfileirados são despachados um de cada vez em um curto intervalo após a chamada para addEventListener() ser retornada. Se um novo evento invoke ocorrer durante esse processo, ele poderá ser despachado antes de um ou mais dos eventos enfileirados. Esse enfileiramento de eventos permite que você manipule qualquer evento invoke que tenha ocorrido antes de seu código de inicialização ser executado. Tenha em mente que, se você adicionar um ouvinte de evento depois na execução (depois da inicialização do aplicativo), ele ainda receberá todos os eventos invoke que ocorreram desde que o aplicativo foi iniciado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 292 Inicialização do aplicativo e opções de saída Apenas uma instância de um aplicativo do AIR é iniciada. Quando um aplicativo já em execução é invocado novamente, o AIR despacha um novo evento invoke para a instância em execução. É de responsabilidade de um aplicativo do AIR responder a um evento invoke e executar a ação apropriada (como abrir uma janela de um novo documento). Um objeto InvokeEvent contém qualquer argumento transmitido ao aplicativo, bem como o diretório a partir do qual o aplicativo foi invocado. Se o aplicativo foi invocado devido a uma associação de tipo de arquivo, todo o caminho para o arquivo será incluído nos argumentos de linha de comando. Da mesma forma, se o aplicativo foi invocado devido a uma atualização de aplicativo, todo o caminho para o arquivo do AIR atualizado será fornecido. Quando vários arquivos são abertos em uma operação, um único objeto InvokeEvent é despachado no Mac OS X. Cada arquivo é incluído na matriz arguments. No Windows e no Linux, um objeto InvokeEvent distinto é despachado para cada arquivo. Seu aplicativo pode manipular eventos invoke registrando um ouvinte com seu objeto NativeApplication: NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvokeEvent); air.NativeApplication.nativeApplication.addEventListener(air.InvokeEvent.INVOKE, onInvokeEvent); E definindo um ouvinte de evento: var arguments:Array; var currentDir:File; public function onInvokeEvent(invocation:InvokeEvent):void { arguments = invocation.arguments; currentDir = invocation.currentDirectory; } Captura de argumentos de linha de comando Os argumentos de linha de comando associados à invocação de um aplicativo do AIR são entregues no evento invoke despachado pelo objeto NativeApplication. A propriedade InvokeEvent.arguments contém uma matriz dos argumentos transmitidos pelo sistema operacional quando um aplicativo do AIR é invocado. Se os argumentos contêm caminhos de arquivos relativos, você pode normalmente resolver os caminhos usando a propriedade currentDirectory. Os argumentos transmitidos a um programa do AIR são tratados como seqüências delimitadas de espaço em branco, a menos que estejam entre aspas duplas: Argumentos Matriz tick tock {tick,tock} tick "tick tock" {tick,tick tock} "tick" “tock” {tick,tock} \"tick\" \"tock\" {"tick","tock"} A propriedade InvokeEvent.currentDirectory contém um objeto File que representa o diretório a partir do qual o aplicativo foi iniciado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 293 Inicialização do aplicativo e opções de saída Quando um aplicativo é invocado porque um arquivo de um tipo registrado pelo aplicativo é aberto, o caminho nativo para o arquivo é incluído nos argumentos de linha de comando como uma seqüência de caracteres. (Seu aplicativo é responsável por abrir ou executar a operação pretendida no arquivo.) Da mesma forma, quando um aplicativo é programado para se atualizar (em vez de confiar na interface de usuário de atualização do AIR padrão), o caminho nativo para o arquivo do AIR é incluído quando um usuário clica duas vezes em um arquivo do AIR que contém um aplicativo com uma ID correspondente do aplicativo. Você pode acessar o arquivo usando o método resolve() do objeto File currentDirectory: if((invokeEvent.currentDirectory != null)&&(invokeEvent.arguments.length > 0)){ dir = invokeEvent.currentDirectory; fileToOpen = dir.resolvePath(invokeEvent.arguments[0]); } Você também deve validar se um argumento é realmente um caminho para um arquivo. Exemplo: log de eventos de invocação O exemplo a seguir demonstra como registrar ouvintes para e manipular o evento invoke. O exemplo registra todos os eventos de invocação recebidos e exibe o diretório atual e os argumentos de linha de comando. Nota: Para criar o seguinte exemplo usando o Adobe® Flash® CS3 Professional ou o Adobe® Flash® CS4 Professional, crie primeiro um arquivo do Flash (Adobe AIR). No painel de configurações do ActionScript 3.0 (Arquivo > Configurações de publicação... > botão Configurações), digite o nome InvokeEventLogExample no campo de classe Document. Salve o arquivo FLA com o nome InvokeEventLogExample.fla. Em seguida, crie um arquivo do ActionScript na mesma pasta. Digite o seguinte código no arquivo do ActionScript e, em seguida, salve o arquivo com o nome InvokeEventLogExample.as. package { import import import import flash.display.Sprite; flash.events.InvokeEvent; flash.desktop.NativeApplication; flash.text.TextField; public class InvokeEventLogExample extends Sprite { public var log:TextField; public function InvokeEventLogExample() { log = new TextField(); log.x = 15; log.y = 15; log.width = 520; log.height = 370; log.background = true; addChild(log); NativeApplication.nativeApplication.addEventListener(InvokeEvent.INVOKE, onInvoke); } public function onInvoke(invokeEvent:InvokeEvent):void { var now:String = new Date().toTimeString(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 294 Inicialização do aplicativo e opções de saída logEvent("Invoke event received: " + now); if (invokeEvent.currentDirectory != null) { logEvent("Current directory=" + invokeEvent.currentDirectory.nativePath); } else { logEvent("--no directory information available--"); } if (invokeEvent.arguments.length > 0) { logEvent("Arguments: " + invokeEvent.arguments.toString()); } else { logEvent("--no arguments--"); } } public function logEvent(entry:String):void { log.appendText(entry + "\n"); trace(entry); } } } Inicialização no login Um aplicativo do AIR pode ser definido para ser inicializado automaticamente quando o usuário atual faz login definindo NativeApplication.nativeApplication.startAtLogin=true. Depois de definido, o aplicativo é iniciado automaticamente sempre que o usuário fizer login. Ele continua a ser aberto na inicialização até que a configuração seja alterada para false, o usuário altera manualmente a configuração pelo sistema operacional ou o aplicativo é desinstalado. A inicialização no login é uma configuração de tempo de execução. Nota: O aplicativo não é iniciado quando o sistema do computador é iniciado. Ele é iniciado quando o usuário faz login. A configuração se aplica apenas ao usuário atual. Além disso, o aplicativo deve ser instalado para definir com êxito a propriedade startAtLogin como true. Um erro é lançado se a propriedade é definida quando um aplicativo não é instalado (como quando ele é inicializado com o ADL). Invocação do navegador Usando o recurso de invocação do navegador, um site da Web pode inicializar um aplicativo instalado do AIR do navegador. A invocação do navegador é permitida apenas se o arquivo do descritor do aplicativo define allowBrowserInvocation como true: <allowBrowserInvocation>true</allowBrowserInvocation> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 295 Inicialização do aplicativo e opções de saída Para obter mais informações sobre o arquivo do descritor do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44. Quando o aplicativo é invocado pelo navegador, o objeto NativeApplication do aplicativo despacha um objeto BrowserInvokeEvent. Para receber eventos BrowserInvokeEvent, chame o método addEventListener() do objeto NativeApplication (NativeApplication.nativeApplication) no aplicativo do AIR. Quando um ouvinte de evento registra um evento BrowserInvokeEvent, ele também recebe todos os eventos BrowserInvokeEvent que ocorreram antes do registro. Esses eventos são despachados depois que a chamada a addEventListener() retorna, mas não necessariamente antes de outros eventos BrowserInvokeEvent, que podem ser recebidos depois do registro. Isso permite que você manipule os eventos BrowserInvokeEvent ocorridos antes que seu código de inicialização fosse executado (por exemplo, quando o aplicativo foi inicialmente invocado do navegador). Tenha em mente que, se você adicionar um ouvinte de evento depois na execução (depois da inicialização do aplicativo), ele ainda receberá todos os eventos BrowserInvokeEvent ocorridos desde que o aplicativo foi iniciado. O objeto BrowserInvokeEvent inclui as seguintes propriedades: Propriedade Descrição argumentos Uma matriz de argumentos (seqüências de caracteres) para transmitir ao aplicativo. isHTTPS Se o conteúdo do navegador usa o esquema de URL https (true) ou não (false). isUserEvent Se a invocação do navegador resultou em um evento de usuário (como clique do mouse). No AIR 1.0, este ajuste é sempre true; o AIR exige um evento de usuário para o recurso de invocação do navegador. sandboxType O tipo de caixa de proteção para o conteúdo do navegador. Valores válidos são definidos como aqueles que podem ser usados na propriedade Security.sandboxType e podem ser um dos seguintes: • • Security.APPLICATION – O conteúdo está na caixa de proteção de segurança do aplicativo. Security.LOCAL_TRUSTED – O conteúdo está na caixa de proteção de segurança local com sistema de arquivos. • Security.LOCAL_WITH_FILE – O conteúdo está na caixa de proteção de segurança local com sistema de arquivos. securityDomain • Security.LOCAL_WITH_NETWORK – O conteúdo está na caixa de proteção de segurança local com rede. • Security.REMOTE — O conteúdo está em um domínio remoto (de rede). O domínio de segurança para o conteúdo do navegador, como "www.adobe.com" ou "www.example.org". Essa propriedade é definida apenas para conteúdo na caixa de proteção de segurança remota (para conteúdo de um domínio de rede). Ele não é definido para conteúdo em uma caixa de proteção de segurança local ou do aplicativo. Se você usa o recurso de invocação do navegador, certifique-se de considerar implicações de segurança. Quando um site da Web inicia um aplicativo do AIR, ele pode enviar dados pela propriedade arguments do objeto BrowserInvokeEvent. Cuidado ao usar esses dados em qualquer operação confidencial, como carregar código ou arquivo de APIs. Esse nível de risco depende do que o aplicativo está fazendo com os dados. Se você espera apenas um site da Web específico para invocar o aplicativo, o aplicativo deve verificar a propriedade securityDomain do objeto BrowserInvokeEvent. Você também pode exigir que o site invoque o aplicativo para usar HTTPs, o que você pode verificar marcando a propriedade isHTTPS do objeto BrowserInvokeEvent. O aplicativo deve validar os dados transmitidos. Por exemplo, se um aplicativo espera para transmitir URLs a um domínio específico, ele deve validar se as URLs realmente apontam para aquele domínio. Isso pode impedir que um invasor engane o aplicativo para lhe enviar dados confidenciais. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 296 Inicialização do aplicativo e opções de saída Nenhum aplicativo deve usar argumentos BrowserInvokeEvent que possam apontar para recursos locais. Por exemplo, um aplicativo não deve criar objetos File com base em um caminho transmitido do navegador. Se espera-se que caminhos remotos sejam transmitidos do navegador, o aplicativo deve garantir que os caminhos não usem o protocolo file:// em vez de um protocolo remoto. Para obter detalhes sobre como invocar um aplicativo do navegador, consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. Encerramento do aplicativo A maneira mais rápida de encerrar um aplicativo é acionar NativeApplication.nativeApplication.exit(), o que funciona bem quando seu aplicativo não tem dados para salvar ou recursos externos para limpar. Chamar exit() fecha todas as janelas e, em seguida, encerra o aplicativo. No entanto, para permitir que janelas ou outros componentes do seu aplicativo interrompam o processo de encerramento, talvez para salvar dados vitais, despache os eventos de aviso adequados antes de chamar exit(). Outra consideração sobre como fechar um aplicativo graciosamente é fornecer um único caminho de execução, sem importar como o processo de encerramento é iniciado. O usuário (ou sistema operacional) pode disparar o encerramento do aplicativo das seguintes maneiras: • Fechando a última janela do aplicativo quando NativeApplication.nativeApplication.autoExit for true. • Selecionando o comando de saída do aplicativo do sistema operacional; por exemplo, quando o usuário escolhe o comando de sair do aplicativo do menu padrão. Isso só ocorre com o Mac OS. O Windows e o Linux não fornecem um comando de saída do aplicativo por meio do cromo de sistema. • Desligando o computador. Quando um comando de saída é mediado pelo sistema operacional por uma dessas rotas, o NativeApplication despacha um evento exiting. Se nenhum ouvinte cancelar o evento exiting, qualquer janela aberta será fechada. Cada janela despacha um evento closing e, em seguida, um close. Se alguma das janelas cancelar o evento closing, o processo de encerramento será interrompido. Se a ordem do fechamento das janelas for um problema para o seu aplicativo, ouça o evento exiting do NativeApplication e feche você mesmo as janelas na ordem adequada. Isso pode ocorrer, por exemplo, se você possuir uma janela de documento com paletas de ferramentas. Pode ser inconveniente, ou pior, se o sistema fechou as paletas, mas o usuário decidiu cancelar o comando de sair para salvar alguns dados. No Windows, o único momento que você obterá o evento exiting é depois de fechar a última janela (quando a propriedade autoExit do objeto NativeApplication for definida como true). Para fornecer um comportamento consistente em todas as plataformas, seja a seqüência de saída iniciada pelo cromo do sistema operacional, por comandos de menu ou pela lógica do aplicativo, observe as seguintes práticas recomendadas para sair do aplicativo: 1 Sempre despache um evento exiting pelo objeto NativeApplication antes de chamar exit() no código do aplicativo e verifique se outro componente do seu aplicativo não cancela o evento. public function applicationExit():void { var exitingEvent:Event = new Event(Event.EXITING, false, true); NativeApplication.nativeApplication.dispatchEvent(exitingEvent); if (!exitingEvent.isDefaultPrevented()) { NativeApplication.nativeApplication.exit(); } } DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 297 Inicialização do aplicativo e opções de saída 2 Ouça o evento exiting do aplicativo do objeto NativeApplication.nativeApplication e, no manipulador, feche qualquer janela (despachando um evento closing primeiro). Execute qualquer tarefa de limpeza necessária, como salvar dados de aplicativo ou excluir arquivos temporários, após todas as janelas terem sido fechadas. Apenas use métodos síncronos durante a limpeza para garantir que eles sejam concluídos antes que o aplicativo seja encerrado. Se a ordem na qual suas janelas forem fechadas não importar, você pode efetuar um loop pela matriz NativeApplication.nativeApplication.openedWindows e fechar cada janela sucessivamente. Se a ordem importar, forneça um modo de fechar as janelas na seqüência correta. private function onExiting(exitingEvent:Event):void { var winClosingEvent:Event; for each (var win:NativeWindow in NativeApplication.nativeApplication.openedWindows) { winClosingEvent = new Event(Event.CLOSING,false,true); win.dispatchEvent(winClosingEvent); if (!winClosingEvent.isDefaultPrevented()) { win.close(); } else { exitingEvent.preventDefault(); } } if (!exitingEvent.isDefaultPrevented()) { //perform cleanup } } 3 As janelas devem sempre manipular sua própria limpeza ouvindo seus próprios eventos closing. 4 Use apenas um ouvinte exiting no seu aplicativo uma vez que manipuladores chamados anteriormente não podem saber se os manipuladores subseqüentes irão cancelar o evento exiting (e não seria inteligente confiar na ordem de execução). Consulte também “Configuração de propriedades do aplicativo do AIR” na página 44 “Apresentação de uma interface de usuário de atualização do aplicativo personalizado” na página 330 298 Capítulo 27: Leitura de configurações do aplicativo No tempo de execução, você pode obter propriedades do arquivo descritor do aplicativo, bem como a ID do editor do aplicativo. Elas são definidas nas propriedades applicationDescriptor e publisherID do objeto NativeApplication. Leitura do arquivo do descritor do aplicativo. Você pode ler o arquivo descritor do aplicativo em execução no momento, como um objeto XML, obtendo a propriedade applicationDescriptor do objeto NativeApplication, conforme segue: var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor; Em seguida, você pode acessar dados do descritor do aplicativo, como um objeto XML (E4X), como no seguinte: var appXml:XML = NativeApplication.nativeApplication.applicationDescriptor; var ns:Namespace = appXml.namespace(); var appId = appXml.ns::id[0]; var appVersion = appXml.ns::version[0]; var appName = appXml.ns::filename[0]; air.trace("appId:", appId); air.trace("version:", appVersion); air.trace("filename:", appName); var xmlString = air.NativeApplication.nativeApplication.applicationDescriptor; Para obter mais informações, consulte “A estrutura do arquivo do descritor do aplicativo” na página 44. Como obter os identificadores de aplicativo e editor As IDs de aplicativo e editor juntas, identificam exclusivamente um aplicativo do AIR. Você especifica a ID do aplicativo no elemento <id> do descritor do aplicativo. A ID de editor é derivada do certificado usado para assinar o pacote de instalação do AIR. A ID do aplicativo pode ser lida da propriedade id do objeto NativeApplication, conforme ilustrado no seguinte código: trace(NativeApplication.nativeApplication.applicationID); A ID do editor pode ser lida da propriedade publisherID do NativeApplication: trace(NativeApplication.nativeApplication.publisherID); Nota: Quando um aplicativo AIR está sendo executado com ADL, ele não tem uma ID de editor, a menos que uma ID seja atribuída temporariamente usando o sinalizador -pubID na linha de comando do ADL. A ID do editor de um aplicativo instalado também pode ser encontrada no arquivo META-INF/AIR/publisherid no diretório de instalação do aplicativo. Para obter mais informações, consulte “Sobre identificadores do editor do AIR” na página 322. 299 Capítulo 28: Trabalho com tempo de execução e informações do sistema operacional Esta seção discute os modos pelos quais um aplicativo AIR pode gerenciar associações de arquivo do sistema operacional, detectar atividade do usuário e obter informações sobre o tempo de execução do Adobe® AIR™. Gerenciamento de associações de arquivos Associações entre seu aplicativo e um tipo de arquivo devem ser declaradas no descritor do aplicativo. Durante o processo de instalação, o instalador do aplicativo AIR associa o aplicativo AIR como o aplicativo de abertura padrão para cada um dos tipos de arquivo declarados, a menos que outro aplicativo já seja o padrão. O processo de instalação do aplicativo AIR não substitui uma associação de tipo de arquivo existente. Para se apoderar da associação de outro aplicativo, chame o método NativeApplication.setAsDefaultApplication() no tempo de execução. Constitui boa prática verificar se as associações de arquivos esperadas estão em vigor quando seu aplicativo inicializar Isso porque o instalador do aplicativo AIR não sobrescreve associações de arquivo existentes e porque associações de arquivo em um sistema de usuário podem mudar a qualquer momento. Quando outro aplicativo tem a associação de arquivo atual, também é boa prática solicitar ao usuário antes de se apoderar de uma associação existente. Os métodos seguintes da classe NativeApplication permitem que um aplicativo gerencie associações de arquivos. Cada um dos métodos toma a extensão de tipo de arquivo como um parâmetro: Método Descrição isSetAsDefaultApplication() Retorna true se o aplicativo AIR está associado atualmente ao tipo de arquivo especificado. setAsDefaultApplication() Cria a associação entre o aplicativo AIR e a ação aberta do tipo de arquivo. removeAsDefaultApplication() Remove a associação entre o aplicativo AIR e o tipo de arquivo. getDefaultApplication() Reporta o caminho do aplicativo que está associado atualmente ao tipo de arquivo. O AIR só pode gerenciar associações para os tipos de arquivo originalmente declarados no descritor do aplicativo. Você não pode obter informações sobre as associações de um tipo de arquivo não declarado, mesmo que um usuário tenha criado manualmente a associação entre esse tipo de arquivo e seu aplicativo. Chamar algum dos métodos de gerenciamento de associação de arquivo com a extensão de um tipo de arquivo não declarado no descritor do aplicativo faz com que o aplicativo lance uma exceção de tempo de execução. Para obter informações sobre declarar tipos de arquivos no descritor do aplicativo, consulte “Declaração de associações de tipo de arquivo” na página 52. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 300 Trabalho com tempo de execução e informações do sistema operacional Obtenção da versão do tempo de execução e do nível de patch O objeto NativeApplication tem uma propriedade runtimeVersion, que é a versão do tempo de execução em que o aplicativo está sendo executado (uma string, como "1.0.5"). O objeto NativeApplication também tem uma propriedade runtimePatchLevel, que é o nível de patch do tempo de execução (um número, como 2960). O código seguinte usa estas propriedades: trace(NativeApplication.nativeApplication.runtimeVersion); trace(NativeApplication.nativeApplication.runtimePatchLevel); Detecção de recursos do AIR Para um arquivo que esteja reunido com o aplicativo Adobe AIR, a propriedade Security.sandboxType está definida como o valor definido pela constante Security.APPLICATION. Você pode carregar o conteúdo (que pode ou não conter APIs específicas ao AIR) baseado em um arquivo estar na caixa de proteção de segurança do Adobe AIR, como ilustrado no código seguinte: if (Security.sandboxType == Security.APPLICATION) { // Load SWF that contains AIR APIs } else { // Load SWF that does not contain AIR APIs } Todos os recursos não instalado com o aplicativo AIR são atribuídos às mesmas caixas de proteção de segurança como seriam atribuídos pelo Adobe® Flash® em um navegador da Web. Recursos remotos são colocados em caixas de proteção, de acordo com seus domínios de origem, e recursos locais são colocados na caixa de proteção local com rede, local com sistema de arquivos ou local confiável. Você pode verificar se a propriedade estática Capabilities.playerType está definida como "Desktop" para ver se o conteúdo está sendo executado no tempo de execução (e não em execução no Flash Player em execução em um navegador). Para obter mais informações, consulte “Segurança do AIR” na página 23. Rastreamento de presença do usuário O objeto NativeApplication despacha dois eventos que o ajudam a detectar quando o usuário está usando o computador ativamente. Se não for detectada nenhuma atividade do mouse nem do teclado no intervalo de tempo determinado pela propriedade NativeApplication.idleThreshold, o NativeApplication despacha um evento userIdle. Quando ocorrer a próxima entrada de mouse ou teclado, o objeto NativeApplication despachará um evento userPresent. O intervalo idleThreshold é medido em segundos e tem um valor padrão de 300 (5 minutos). Você também ode obter o número de segundos desde a última entrada de usuário da propriedade NativeApplication.nativeApplication.lastUserInput. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 301 Trabalho com tempo de execução e informações do sistema operacional As linhas seguintes de código definem o limite de ociosidade para 2 minutos e ouvem tanto eventos userIdle como userPresent: NativeApplication.nativeApplication.idleThreshold = 120; NativeApplication.nativeApplication.addEventListener(Event.USER_IDLE, function(event:Event) { trace("Idle"); }); NativeApplication.nativeApplication.addEventListener(Event.USER_PRESENT, function(event:Event) { trace("Present"); }); Nota: Apenas um único evento userIdle é despachado entre quaisquer dois eventos userPresent. 302 Capítulo 29: Monitoramento de conectividade de rede O Adobe® AIR™ oferece os meios para verificar alterações na conectividade de rede do computador em que um aplicativo AIR esteja instalado. Essa informação é útil caso um aplicativo utilize dados obtidos da rede. Além disso, o aplicativo pode verificar a disponibilidade de um serviço de rede. Detecção de alterações na conectividade de rede Seu aplicativo AIR pode ser executado em ambientes com conectividade de rede incerta e em mudança. Para ajudar um aplicativo a gerenciar conexões em recursos on-line, o Adobe AIR envia um evento de mudança de rede sempre que uma conexão de rede se torna disponível ou indisponível. O objeto NativeApplication do aplicativo despacha o evento de mudança de rede. Para reagir a esse evento, adicione um ouvinte: NativeApplication.nativeApplication.addEventListener(Event.NETWORK_CHANGE, onNetworkChange); E defina uma função do manipulador de eventos: function onNetworkChange(event:Event) { //Check resource availability } O evento Event.NETWORK_CHANGE não indica uma mudança em toda a atividade de rede, mas apenas que uma conexão de rede sofreu mudança. O AIR não tenta interpretar o significado da mudança de rede. Um computador em rede pode ter várias conexões reais e virtuais, portanto, perder uma conexão não significa necessariamente perder um recurso. Por outro lado, novas conexões também não garantem melhor disponibilidade de recursos. Às vezes uma nova conexão pode até bloquear o acesso a recursos anteriormente disponíveis (por exemplo, ao se conectar a uma VPN). Em geral, a única maneira de um aplicativo determinar se ele pode se conectar a um recurso remoto é por tentativa. Para essa finalidade, as estruturas de monitoramento de serviço do pacote air.net fornecem aplicativos AIR com um meio baseado em evento de responder às mudanças na conectividade de rede para um host especificado. Nota: A estrutura de monitoramento de serviço detecta se um servidor responde de maneira aceitável a uma solicitação. Isso não garante conectividade total. Serviços dimensionáveis da Web geralmente usam aparatos de cache e balanceamento de carga para redirecionar o tráfego para um cluster de servidores Web. Nessa situação, provedores de serviço só oferecem um diagnóstico parcial de conectividade de rede. Noções básicas de monitoramento de serviço A estrutura de monitor de serviço, separada da estrutura do AIR, reside no arquivo servicemonitor.swc. Para usar a estrutura, o arquivo servicemonitor.swc deve ser incluído em seu processo de construção. Importante: Para usar essas classes no Adobe® Flash® CS3 Professional, arraste o componente ServiceMonitorShim do painel Componentes para a Biblioteca e, em seguida, adicione a seguinte declaração import ao código do ActionScript 3.0: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 303 Monitoramento de conectividade de rede import air.net.*; Para usar essas classes no Adobe® Flash® CS4 Professional: 1 Selecione o comando Arquivo > Configurações de publicação. 2 Clique no botão Configurações do ActionScript 3.0. Selecione Caminho da biblioteca. 3 Clique no botão Procurar SWC e procure por Adobe Flash CS4/AIK1.1/frameworks/libs/air/servicemoniter.swc. 4 Clique no botão OK. 5 Adicione a seguinte instrução de importação ao código do ActionScript 3.0: import air.net.*; A classe ServiceMonitor implementa a estrutura para monitorar serviços de rede e oferece uma funcionalidade básica para monitores de serviço. Por padrão, uma ocorrência da classe ServiceMonitor despacha eventos relacionados à conectividade de rede. O objeto ServiceMonitor despacha esses eventos quando a ocorrência é criada e sempre que uma mudança de rede é detectada pelo Adobe AIR. Além disso, você pode definir a propriedade pollInterval de uma ocorrência ServiceMonitor para verificar a conectividade em um intervalo especificado em milissegundos, independentemente de eventos gerais de conectividade de rede. Um objeto ServiceMonitor não verifica a conectividade de rede até que o método start() seja chamado. A classe URLMonitor, uma subclasse da classe ServiceMonitor, detecta mudanças na conectividade HTTP para um URLRequest especificado. A classe SocketMonitor, também uma subclasse da classe ServiceMonitor, detecta mudanças na conectividade em um host especificado de uma porta especificada. Detecção de conectividade HTTP A classe URLMonitor determina se podem ser feitas solicitações HTTP a um endereço especificado na porta 80 (a porta típica para comunicação HTTP). O código seguinte usa uma instância da classe URLMonitor para detectar mudanças de conectividade no site da Adobe: import air.net.URLMonitor; import flash.net.URLRequest; import flash.events.StatusEvent; var monitor:URLMonitor; monitor = new URLMonitor(new URLRequest('http://www.adobe.com')); monitor.addEventListener(StatusEvent.STATUS, announceStatus); monitor.start(); function announceStatus(e:StatusEvent):void { trace("Status change. Current status: " + monitor.available); } Detecção de conectividade de soquete Aplicativos AIR também podem usar conexões de soquete para conectividade modelo empurrar. Firewalls e roteadores de rede geralmente restringem a comunicação em rede em portas não autorizadas, por questões de segurança. Por esse motivo, os desenvolvedores devem considerar que usuários podem não ter recursos para fazer conexões de rede. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 304 Monitoramento de conectividade de rede Semelhante ao exemplo URLMonitor, o código seguinte usa uma ocorrência da classe SocketMonitor para detectar mudanças na conectividade em uma conexão de soquete em 6667, uma porta comum do IRC: import air.net.ServiceMonitor; import flash.events.StatusEvent; socketMonitor = new SocketMonitor('www.adobe.com',6667); socketMonitor.addEventListener(StatusEvent.STATUS, socketStatusChange); socketMonitor.start(); function announceStatus(e:StatusEvent):void { trace("Status change. Current status: " + socketMonitor.available); } 305 Capítulo 30: Solicitações de URL e rede A nova funcionalidade do Adobe AIR relacionada à especificação de solicitações de URL não está disponível para conteúdo SWF executado no navegador. Essa funcionalidade só está disponível para conteúdo na caixa de proteção de segurança do aplicativo. Esta seção descreve os recursos de URLRequest no tempo de execução e analisa como a API de rede altera o conteúdo do AIR. Para obter outras informações sobre o uso dos recursos de rede e comunicação do Adobe® ActionScript® 3.0, consulte Programação do Adobe ActionScript 3.0. Uso da classe URLRequest Com a classe URLRequest, você pode definir mais do que simplesmente a string da URL. O AIR adicionou algumas novas propriedades à classe URLRequest, que só estão disponíveis para conteúdo do AIR executado na caixa de proteção de segurança do aplicativo. O conteúdo no tempo de execução pode definir URLs usando novos esquemas de URL (além de esquemas padrão, como file e http). Propriedades de URLRequest A classe URLRequest inclui as seguintes propriedades, que estão disponíveis para conteúdo somente na caixa de proteção de segurança de aplicativos do AIR: Propriedade Descrição followRedirects Especifica se os redirecionamentos devem ser seguidos (true, o valor padrão) ou não (false). Esta propriedade só é suportada no tempo de execução. manageCookies Especifica se a pilha de protocolo HTTP deve gerenciar cookies (true, o valor padrão) ou não (false) desta solicitação. Esta propriedade só é suportada no tempo de execução. authenticate Especifica se as solicitações de autenticação relativas a esta solicitação devem ser manipuladas (true). Esta propriedade só é suportada no tempo de execução. O padrão é autenticar as solicitações, o que pode fazer com que seja exibida uma caixa de diálogo de autenticação se o servidor exigir a apresentação das credenciais. Também é possível definir o nome de usuário e a senha (consulte “Configuração de padrões de URLRequest” na página 306. cacheResponse Especifica se os dados de respostas bem-sucedidas relacionados a esta solicitação devem ser armazenados em cache. Esta propriedade só é suportada no tempo de execução. O padrão é armazenar a resposta em cache (true). useCache Especifica se o cache local deve ser consultado antes que URLRequest saia em busca dos dados. Esta propriedade só é suportada no tempo de execução. O padrão (true) é usar a versão armazenada no cache local, se disponível. userAgent Especifica a string user-agent a ser usada na solicitação HTTP. As seguintes propriedades de um objeto URLRequest podem ser definidas por conteúdo em qualquer caixa de proteção (e não somente na caixa de proteção de segurança de aplicativos do AIR): DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 306 Solicitações de URL e rede Propriedade Descrição contentType O tipo de conteúdo MIME de qualquer dado enviado com a solicitação de URL. data Um objeto contendo dados a serem transmitidos com a solicitação de URL. digest Uma "compilação" segura em um arquivo em cache que monitora o cache do Adobe® Flash® Player. method Controla o método de solicitação HTTP, como uma operação GET ou POST. (O conteúdo em execução no domínio de segurança do aplicativo do AIR pode especificar strings diferentes de "GET" ou "POST" como a propriedade method. É permitido qualquer verbo HTTP, e "GET" é o método padrão. Consulte “Segurança do AIR” na página 23.) requestHeaders A matriz de cabeçalhos de solicitação HTTP a ser acrescentada à solicitação HTTP. url Especifica a URL a ser solicitada. Nota: A classe HTMLLoader tem propriedades relacionadas para configurações que pertencem ao conteúdo carregado por um objeto HTMLLoader. Para obter detalhes, consulte “Sobre a classe HTMLLoader” na página 233 . Configuração de padrões de URLRequest A classe URLRequestDefaults permite definir configurações padrão para objetos URLRequest. Por exemplo, o código abaixo define os valores padrão para as propriedades manageCookies e useCache: URLRequestDefaults.manageCookies = false; URLRequestDefaults.useCache = false; air.URLRequestDefaults.manageCookies = false; air.URLRequestDefaults.useCache = false; A classe URLRequestDefaults inclui um método setLoginCredentialsForHost() que permite especificar um nome de usuário e uma senha padrão para uso em um determinado host. O host, definido no parâmetro hostname do método, pode ser um domínio, como "www.example.com", ou um domínio e um número de porta, como "www.example.com:80". Observe que "example.com", "www.example.com" e "sales.example.com" são todos considerados hosts únicos. Essas credenciais só serão utilizadas se exigidas pelo servidor. Se o usuário já foi autenticado (por exemplo, usando a caixa de diálogo de autenticação), você não poderá alterar o usuário autenticado chamando o método setLoginCredentialsForHost(). Por exemplo, o seguinte código define o nome de usuário e a senha padrão que devem ser utilizados em www.example.com: URLRequestDefaults.setLoginCredentialsForHost("www.example.com", "Ada", "love1816$X"); air.URLRequestDefaults.setLoginCredentialsForHost("www.example.com", "Ada", "love1816$X"); Cada propriedade de configurações URLRequestDefaults aplica-se somente ao domínio de aplicativo do conteúdo que define a propriedade. No entanto, o método setLoginCredentialsForHost() aplica-se ao conteúdo em todos os domínios de aplicativo dentro de um aplicativo do AIR. Dessa maneira, um aplicativo pode fazer logon em um host e ter todo o conteúdo no aplicativo conectado com as credenciais especificadas. Para obter mais informações, consulte a classe URLRequestDefaults na Referência dos componentes e da linguagem do ActionScript 3.0 (http://www.adobe.com/go/learn_air_aslr_br). Uso de esquemas de URL do AIR em URLs Os esquemas de URL padrão, como os seguintes, estão disponíveis quando são definidas URLs em qualquer caixa de proteção de segurança do AIR: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 307 Solicitações de URL e rede http: e https: Use-os da mesma forma que você os utilizaria em um navegador da Web. file: Use para especificar um caminho relativo à raiz do sistema de arquivos. Por exemplo: file:///c:/AIR Test/test.txt Também é possível utilizar os seguintes esquemas ao definir uma URL para conteúdo em execução na caixa de proteção de segurança do aplicativo: app: Use para especificar um caminho relativo ao diretório raiz do aplicativo instalado (o diretório que contém o arquivo de descrição do aplicativo instalado). Por exemplo, o seguinte caminho aponta para um subdiretório de recursos do diretório do aplicativo instalado: app:/resources Quando executado no aplicativo ADL, o diretório de recursos do aplicativo é definido como o diretório que contém o arquivo de descrição do aplicativo. app-storage: Use para especificar um caminho relativo ao diretório de armazenamento do aplicativo. Para cada aplicativo instalado, o AIR define um diretório de armazenamento do aplicativo exclusivo para cada usuário, que é um local útil para armazenar dados específicos desse aplicativo. Por exemplo, o caminho a seguir aponta para o arquivo prefs.xml em um subdiretório de configurações do diretório de armazenamento do aplicativo: app-storage:/settings/prefs.xml A localização do diretório de armazenamento do aplicativo baseia-se no nome do usuário, na ID do aplicativo e na ID do editor: • No Mac OS, em: /Users/user name/Library/Preferences/applicationID.publisherID/Local Store/ Por exemplo: /Users/babbage/Library/Preferences/com.example.TestApp.02D88EEED35F84C264A183921344EEA353 A629FD.1/Local Store • No Windows: no diretório Documents and Settings, em: user name/Application Data/applicationID.publisherID/Local Store/ Por exemplo: C:\Documents and Settings\babbage\Application Data\com.example.TestApp.02D88EEED35F84C264A183921344EEA353A629FD.1\Local Store • No Linux - In: /home/user name/.appdata/applicationID.publisherID/Local Store/ Por exemplo: /home/babbage/.appdata/com.example.TestApp.02D88EEED35F84C264A183921344EEA353A629FD.1\Loc al Store DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 308 Solicitações de URL e rede A URL (e a propriedade url) de um objeto File criado com File.applicationStorageDirectory usa o esquema de URL app-storage, como abaixo: var dir:File = File.applicationStorageDirectory; dir = dir.resolvePath("preferences"); trace(dir.url); // app-storage:/preferences var dir = air.File.applicationStorageDirectory; dir = dir.resolvePath("prefs.xml"); air.trace(dir.url); // app-storage:/preferences mailto: Você pode usar o esquema mailto em objetos URLRequests enviados para a função navigateToURL(). Consulte “Abertura de uma URL no navegador da Web padrão do sistema” na página 308. Uso de esquemas de URL no AIR Você pode usar um objeto URLRequest que utilize qualquer um desses esquemas de URL para definir a solicitação de URL para inúmeros objetos diferentes, como FileStream ou Sound. Também é possível usar esses esquemas em um conteúdo HTML em execução no AIR; por exemplo, você pode usá-los no atributo src de uma tag img. Porém, você só pode usar estes esquemas de URL específicos do AIR (app: e app-storage:) no conteúdo localizado na caixa de proteção de segurança do aplicativo. Para obter mais informações, consulte “Segurança do AIR” na página 23. Esquemas de URL proibidos Algumas APIs permitem iniciar conteúdo em um navegador da Web. Por motivo de segurança, alguns esquemas de URL são proibidos quando essas APIs são utilizadas no AIR. A lista de esquemas proibidos depende da caixa de proteção de segurança do código que usa a API. Para obter detalhes, consulte “Abertura de uma URL no navegador da Web padrão do sistema” na página 308 . Alterações feitas na classe URLStream A classe URLStream fornece acesso de baixo nível para download de dados de URLs. No tempo de execução, a classe URLStream inclui um novo evento: httpResponseStatus. Diferentemente do evento httpStatus, o evento httpResponseStatus é fornecido antes de qualquer dado de resposta. O evento httpResponseStatus (definido na classe HTTPStatusEvent) inclui uma propriedade responseURL, que é a URL da qual a resposta foi retornada, e uma propriedade responseHeaders, que é uma matriz de objetos URLRequestHeader representando os cabeçalhos de resposta retornados pela resposta. Abertura de uma URL no navegador da Web padrão do sistema Você pode usar a função navigateToURL() para abrir uma URL no navegador da Web padrão do sistema. Para o objeto URLRequest que você passar como o parâmetro request desta função, só é usada a propriedade url. var url = "http://www.adobe.com"; var urlReq = new air.URLRequest(url); air.navigateToURL(urlReq); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 309 Solicitações de URL e rede Nota: Na utilização da função navigateToURL(), o tempo de execução trata um objeto URLRequest que usa o método POST (um que tenha a propriedade method definida como URLRequestMethod.POST) Quando é usada a função navigateToURL(), são permitidos esquemas de URL baseados na caixa de proteção de segurança do código chamando-se a função navigateToURL(). Algumas APIs permitem iniciar conteúdo em um navegador da Web. Por motivo de segurança, alguns esquemas de URL são proibidos quando essas APIs são utilizadas no AIR. A lista de esquemas proibidos depende da caixa de proteção de segurança do código que usa a API. (Para obter detalhes sobre caixas de proteção de segurança, consulte “Segurança do AIR” na página 23.) Caixa de proteção do aplicativo Os esquemas abaixo são permitidos. Use-os da mesma forma que você os utilizaria em um navegador da Web. • http: • https: • file: • mailto: — O AIR direciona essas solicitações para o aplicativo de email do sistema registrado • app: • app-storage: Todos os demais esquemas de URL são proibidos. Caixa de proteção remota Os esquemas abaixo são permitidos. Use-os da mesma forma que você os utilizaria em um navegador da Web. • http: • https: • mailto: — O AIR direciona essas solicitações para o aplicativo de email do sistema registrado Todos os demais esquemas de URL são proibidos. Caixa de proteção Local com arquivo Os esquemas abaixo são permitidos. Use-os da mesma forma que você os utilizaria em um navegador da Web. • file: • mailto: — O AIR direciona essas solicitações para o aplicativo de email do sistema registrado Todos os demais esquemas de URL são proibidos. Caixa de proteção Local com rede Os esquemas abaixo são permitidos. Use-os da mesma forma que você os utilizaria em um navegador da Web. • http: • https: • mailto: — O AIR direciona essas solicitações para o aplicativo de email do sistema registrado Todos os demais esquemas de URL são proibidos. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 310 Solicitações de URL e rede Caixa de proteção Local confiável Os esquemas abaixo são permitidos. Use-os da mesma forma que você os utilizaria em um navegador da Web. • file: • http: • https: • mailto: — O AIR direciona essas solicitações para o aplicativo de email do sistema registrado Todos os demais esquemas de URL são proibidos. 311 Capítulo 31: Comunicação entre aplicativos A classe LocalConnection permite comunicações entre aplicativos Adobe® AIR™, bem como entre aplicativos AIR e conteúdo SWF em execução no navegador. O método connect() da classe LocalConnection usa um parâmetro connectionName para identificar aplicativos. No conteúdo em execução na caixa de proteção de segurança do aplicativo AIR (conteúdo instalado com o aplicativo AIR), o AIR usa a string app# seguida pela ID do aplicativo, seguida por um caractere de ponto (.), seguido pela ID do editor para o aplicativo AIR (definido no arquivo do descritor do aplicativo) no lugar do domínio usado pelo conteúdo SWF em execução no navegador. Por exemplo, um connectionName para um aplicativo com a ID de aplicativo com.example.air.MyApp, o connectionName e a ID do editor B146A943FBD637B68C334022D304CEA226D129B4 é resolvido para"app#com.example.air.MyApp.B146A943FBD637B68C334022D304CEA226D129B4:connectionName". (Para obter mais informações, consulte Definição das informações básicas do aplicativo e “Como obter os identificadores de aplicativo e editor” na página 298.) Quando você permite que outro aplicativo AIR se comunique com seu aplicativo pela conexão local, é preciso chamar o allowDomain() do objeto LocalConnection, passando o nome de domínio da conexão local. Para um aplicativo AIR, esse nome de domínio é formado a partir das IDs do aplicativo e do editor, da mesma forma que na string de conexão. Por exemplo, se o aplicativo AIR de envio tem uma ID de aplicativo de com.example.air.FriendlyApp e uma ID de editor de 214649436BD677B62C33D02233043EA236D13934, a string de domínio a usar para permitir que esse aplicativo se conecte é: app#com.example.air.FriendlyApp.214649436BD677B62C33D02233043EA236D13934. Nota: Ao executar seu aplicativo com ADL (ou outra ferramenta de desenvolvimento, como o Flash CS3, Flex Builder ou Dreamweaver), a ID do editor será nula e deverá ser omitida da string do domínio. Ao instalar e executar seu aplicativo, a ID do editor deverá ser incluída na string do domínio. Você pode atribuir uma ID do editor temporária usando os argumentos de linha de comando do ADL. Use uma ID do editor temporária para testar se a string de conexão e o nome de domínio estão formatados corretamente. 312 Capítulo 32: Distribuição, instalação e execução de aplicativos do AIR Os aplicativos do AIR são distribuídos como um único arquivo de instalação do AIR, que contém o código do aplicativo e todos os ativos. Você pode distribuir esse arquivo por qualquer um dos meios típicos, como por download, e-mail ou mídia física, como CD-ROM. Os usuários podem instalar o aplicativo clicando duas vezes no arquivo do AIR. Você pode usar o recurso de instalação direta, que permite aos usuários instalar seu aplicativo do AIR (e o Adobe® AIR™, se necessário) clicando em um único link em uma página da Web. Antes que ele possa ser distribuído, um arquivo de instalação do AIR deve ser empacotado e assinado com um certificado de assinatura de código e uma chave privada. Assinar digitalmente o arquivo de instalação fornece a garantia de que o seu aplicativo não foi alterado desde que ele foi assinado. Além disso, se uma autoridade de certificação confiável emitiu o certificado digital, seus usuários podem confirmar sua identidade como o editor e signatário. O arquivo do AIR é assinado quando o aplicativo é empacotado com a ferramenta para desenvolvedores do AIR (ADT). Para obter informações sobre como empacotar um aplicativo em um arquivo do AIR usando a atualização do AIR para Flash, consulte “Criação de arquivos do aplicativo AIR e do instalador” na página 15. Para obter informações sobre como empacotar um aplicativo em um arquivo do AIR usando o SDK do Adobe® AIR™, consulte “Empacotamento de um arquivo de instalação do AIR usando o ADT (ferramenta para desenvolvedores do AIR)” na página 357. Instalação e execução de um aplicativo do AIR da área de trabalho Você pode simplesmente enviar o arquivo do AIR ao destinatário. Por exemplo, você pode enviar o arquivo do AIR como um anexo de e-mail ou um link em uma página da Web. Depois que o usuário baixar o aplicativo do AIR, ele deverá seguir estas instruções para instalá-lo: 1 Clique duas vezes no arquivo do AIR. O Adobe AIR já deve estar instalado no computador. 2 Na janela de instalação, deixe as configurações padrão selecionadas e clique em Continuar. No Windows, o AIR faz automaticamente o seguinte: • Instala o aplicativo no diretório Arquivos de Programas • Cria um atalho na área de trabalho para o aplicativo • Cria um atalho no menu Iniciar • Adiciona uma entrada para o aplicativo no Painel de Controle Adicionar ou Remover Programas No Mac OS, por padrão, o aplicativo é adicionado ao diretório Aplicativos. Se o aplicativo já estiver instalado, o instalador oferece ao usuário a opção de abrir a versão existente do aplicativo ou atualizar para a versão no arquivo do AIR obtido por download. O instalador identifica o aplicativo usando a ID do aplicativo e a ID do editor no arquivo do AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 313 Distribuição, instalação e execução de aplicativos do AIR 3 Quando a instalação estiver concluída, clique em Concluir. No Mac OS, para instalar uma versão atualizada de um aplicativo, o usuário precisa de privilégios adequados do sistema para instalar no diretório do aplicativo. No Windows e no Linux, um usuário precisa de privilégios administrativos. Um aplicativo também pode instalar uma versão nova via ActionScript ou JavaScript. Para obter mais informações, consulte “Atualização de aplicativos do AIR” na página 328. Depois que o aplicativo do AIR está instalado, um usuário simplesmente clica duas vezes no ícone do aplicativo para executá-lo, como qualquer outro aplicativo de área de trabalho. • No Windows, clique duas vezes no ícone do aplicativo (que está instalado na área de trabalho ou em uma pasta) ou selecione o aplicativo no menu Iniciar. • No Linux, clique duas vezes no ícone do aplicativo (que está instalado na área de trabalho ou em uma pasta) ou selecione o aplicativo no menu aplicativos. • No Mac OS, clique duas vezes no aplicativo na pasta em que ele foi instalado. O diretório de instalação padrão é o diretório /Aplicativos. O recurso de instalação direta do AIR permite que um usuário instale um aplicativo do AIR clicando em um link em uma página da Web. O recurso de invocação do navegador do AIR permite que um usuário execute um aplicativo do AIR instalado clicando em um link em uma página da Web. Esses recursos são descritos na seção a seguir. Instalação e execução de aplicativos do AIR de uma página da Web O recurso de instalação direta permite que você incorpore um arquivo SWF em uma página da Web que permite ao usuário instalar um aplicativo do AIR do navegador. Se o tempo de execução não for instalado, o recurso de instalação direta instalará o tempo de execução. O recurso de instalação direta permite que usuários instalem o aplicativo do AIR sem salvar o arquivo do AIR em seus computadores. Incluído no SDK do AIR está um arquivo badge.swf, que permite a você usar facilmente o recurso de instalação direta. Para obter detalhes, consulte “Usando o arquivo badge.swf para instalar um aplicativo do AIR” na página 314. Para obter uma demonstração de como usar o recurso de instalação direta, consulte o artigo de amostra de início rápido Distribuição de um aplicativo do AIR pela Web (http://www.adobe.com/go/learn_air_qs_seamless_install_en). Sobre a personalização de badge.swf para instalação direta Além de usar o arquivo badge.swf fornecido com o SDK, você pode criar seu próprio arquivo SWF para usar em uma página do navegador. Seu arquivo SWF personalizado pode interagir com o tempo de execução das seguintes maneiras: • Ele pode instalar um aplicativo do AIR. Consulte “Instalação de um aplicativo do AIR do navegador” na página 319. • Ele pode verificar se um aplicativo do AIR específico está instalado. Consulte “Verificar por uma página da Web se um aplicativo do AIR está instalado” na página 318. • Ele pode verificar se o tempo de execução está instalado. Consulte “Verificar se o tempo de execução está instalado” na página 317. • Ele pode iniciar um aplicativo do AIR instalado no sistema do usuário. Consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 314 Distribuição, instalação e execução de aplicativos do AIR Esses recursos são todos fornecidos ao chamar as APIs em um arquivo SWF hospedado em adobe.com: air.swf. Esta seção descreve como usar e personalizar o arquivo badge.swf e como chamar as APIs do air.swf do seu próprio arquivo SWF. Além disso, um arquivo SWF em execução no navegador pode se comunicar com um aplicativo do AIR em execução usando a classe LocalConnection. Para obter mais informações, consulte “Comunicação entre aplicativos” na página 311. Importante: Os recursos descritos nesta seção (e as APIs no arquivo air.swf) exigem que o usuário final tenha a atualização 3 do Adobe® Flash® Player 9 instalada no navegador da Web no Windows ou Mac OS. No Linux, o recurso de instalação contínua requer o Flash Player 10 (versão 10,0,12,36 ou posterior). Você pode escrever códigos para verificar a versão instalada do Flash Player e fornecer uma interface alternativa ao usuário se a versão exigida do Flash Player não for instalada. Por exemplo, se uma versão mais antiga do Flash Player for instalada, você poderia fornecer um link para a versão de download do arquivo do AIR (em vez de usar o arquivo badge.swf ou a API do air.swf para instalar um aplicativo). Usando o arquivo badge.swf para instalar um aplicativo do AIR Incluído no SDK do AIR está um arquivo badge.swf, que permite a você usar facilmente o recurso de instalação direta. O badge.swf pode instalar o tempo de execução e um aplicativo do AIR de um link em uma página da Web. O arquivo badge.swf e seu código-fonte são fornecidos a você para distribuição no seu site da Web. As instruções nesta seção fornecem informações sobre a definição de parâmetros do arquivo badge.swf fornecido pela Adobe. Também fornecemos o código-fonte para o arquivo badge.swf, que você pode personalizar. Incorporação do arquivo badge.swf em uma página da Web 1 Localize os arquivos a seguir, fornecidos no diretório de exemplos/crachás do SDK do AIR, e adicione-os ao seu servidor Web. • badge.swf • default_badge.html • AC_RunActiveContent.js 2 Abra a página default_badge.html em um editor de texto. 3 Na página default_badge.html, na função JavaScript AC_FL_RunContent(), ajuste as definições do parâmetro FlashVars para as seguintes: Parâmetro Descrição appname O nome do aplicativo, exibido pelo arquivo SWF quando o tempo de execução não está instalado. appurl (Obrigatório). A URL do arquivo do AIR a ser obtido por download. Você deve usar uma URL absoluta, e não relativa. airversion (Obrigatório). Para a versão 1.0 do tempo de execução, defina isso para 1.0. imageurl A URL da imagem (opcional) para exibir no crachá. buttoncolor A cor do botão de download (especificada como um valor hexadecimal, como FFCC00). messagecolor A cor da mensagem de texto exibida abaixo do botão quando o tempo de execução não está instalado (especificada como um valor hexadecimal, como FFCC00). 4 O tamanho mínimo do arquivo badge.swf é de 217 pixels de largura por 180 pixels de altura. Ajuste os valores dos parâmetros width e height da função AC_FL_RunContent() para se adequar às suas necessidades. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 315 Distribuição, instalação e execução de aplicativos do AIR 5 Renomeie o arquivo default_badge.html e ajuste seu código (ou inclua-o em outra página HTML) para se adequar às suas necessidades. Você também pode editar e recompilar o arquivo badge.swf. Para obter detalhes, consulte “Modificação do arquivo badge.swf” na página 315. Instalação do aplicativo do AIR de um link de instalação direta em uma página da Web Depois de ter adicionado o link de instalação direta a uma página, o usuário pode instalar o aplicativo do AIR clicando no link no arquivo SWF. 1 Navegue até a página HTML em um navegador da Web que tenha Flash Player (versão 9 atualização 3 ou posterior no Windows e Mac OS ou versão 10 no Linux) instalada. 2 Na página da Web, clique no link no arquivo badge.swf. • Se tiver instalado o tempo de execução, passe para a próxima etapa. • Se não tiver instalado o tempo de execução, uma caixa de diálogo será exibida perguntando se você gostaria de instalá-lo. Instale o tempo de execução (consulte “Instalação do Adobe AIR” na página 1) e continue com a etapa seguinte. 3 Na janela de instalação, deixe as configurações padrão selecionadas e clique em Continuar. Em um computador Windows, o AIR faz automaticamente o seguinte: • Instala o aplicativo em c:\Arquivos de Programas\ • Cria um atalho na área de trabalho para o aplicativo • Cria um atalho no menu Iniciar • Adiciona uma entrada para o aplicativo no Painel de Controle Adicionar ou Remover Programas No Mac OS, o instalador adiciona o aplicativo ao diretório Aplicativos (por exemplo, no diretório /Aplicativos no Mac OS). Em um computador Linux, o AIR faz automaticamente o seguinte: • Instala o aplicativo na /saída. • Cria um atalho na área de trabalho para o aplicativo • Cria um atalho no menu Iniciar • Adicione uma entrada para o aplicativo no gerenciador de pacotes do sistema 4 Selecione as opções desejadas e clique no botão Instalar. 5 Quando a instalação estiver concluída, clique em Concluir. Modificação do arquivo badge.swf O SDK do AIR fornece os arquivos de origem para o arquivo badge.swf. Esses arquivos estão incluídos na pasta samples/badge do SDK: Arquivos de origem Descrição badge.fla O arquivo de origem do Flash usado para compilar o arquivo badge.swf. O arquivo badge.fla é compilado em um arquivo do SWF 9 (que pode ser carregado no Flash Player). AIRBadge.as Uma classe do ActionScript 3.0 que define a classe base usada no arquivo basdge.fla. Você pode usar o Flash CS3 ou o Flash CS4 para reprojetar a interface visual do arquivo badge.fla. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 316 Distribuição, instalação e execução de aplicativos do AIR A função de construtor AIRBadge(), definida na classe AIRBadge, carrega o arquivo air.swf hospedado em http://airdownload.adobe.com/air/browserapi/air.swf. O arquivo air.swf inclui código para usar o recurso de instalação direta. O método onInit() (na classe AIRBadge) é invocado quando o arquivo air.swf é carregado com sucesso: private function onInit(e:Event):void { _air = e.target.content; switch (_air.getStatus()) { case "installed" : root.statusMessage.text = ""; break; case "available" : if (_appName && _appName.length > 0) { root.statusMessage.htmlText = "<p align='center'><font color='#" + _messageColor + "'>In order to run " + _appName + ", this installer will also set up Adobe® AIR™.</font></p>"; } else { root.statusMessage.htmlText = "<p align='center'><font color='#" + _messageColor + "'>In order to run this application, " + "this installer will also set up Adobe® AIR™.</font></p>"; } break; case "unavailable" : root.statusMessage.htmlText = "<p align='center'><font color='#" + _messageColor + "'>Adobe® AIR™ is not available for your system.</font></p>"; root.buttonBg_mc.enabled = false; break; } } O código define a variável global _air para a classe principal do arquivo air.swf carregado. Essa classe inclui os seguintes métodos públicos, que o arquivo badge.swf acessa para chamar a funcionalidade de instalação direta: Método Descrição getStatus() Determina se o tempo de execução é instalado (ou pode ser instalado) no computador. Para obter detalhes, consulte “Verificar se o tempo de execução está instalado” na página 317. installApplication() Instala o aplicativo especificado na máquina do usuário. Para obter detalhes, consulte “Instalação de um aplicativo do AIR do navegador” na página 319. • url — Uma seqüência de caracteres que define a URL. Você deve usar um caminho de URL absoluta, e não relativa. • runtimeVersion — Uma string que indica a versão do tempo de execução (como "1.0.M6") exigida pelo aplicativo a ser instalado. • arguments — Argumentos a serem transmitidos ao aplicativo se ele for iniciado na instalação. O aplicativo é iniciado na instalação se o elemento allowBrowserInvocation é definido como true no arquivo do descritor do aplicativo. (Para obter mais informações sobre o arquivo do descritor do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44.) Se o aplicativo for iniciado como resultado de uma instalação direta do navegador (com o usuário optando por iniciar na instalação), o objeto NativeApplication do aplicativo despacha um objeto BrowserInvokeEvent apenas se argumentos forem transmitidos. Considere as implicações de segurança de dados que você transmite ao aplicativo. Para obter detalhes, consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. As configurações para url e runtimeVersion são transmitidas no arquivo SWF pelas configurações do FlashVars na página HTML do contêiner. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 317 Distribuição, instalação e execução de aplicativos do AIR Se o aplicativo for iniciado automaticamente na instalação, você poderá usar a comunicação LocalConnection para ter o aplicativo instalado. Entre em contato com o arquivo badge.swf na invocação. Para obter detalhes, consulte “Comunicação entre aplicativos” na página 311. Você também pode chamar o método getApplicationVersion() do arquivo air.swf para verificar se um aplicativo está instalado. Você pode chamar esse método antes do processo de instalação do aplicativo ou após a instalação ser iniciada. Para obter detalhes, consulte “Verificar por uma página da Web se um aplicativo do AIR está instalado” na página 318. Carregar o arquivo air.swf Você pode criar seu próprio arquivo do SWF que usa as APIs no arquivo air.swf para interagir com o tempo de execução e aplicativos do AIR de uma página da Web em um navegador. O arquivo air.swf é hospedado em http://airdownload.adobe.com/air/browserapi/air.swf. Para se referir às APIs do air.swf do seu arquivo SWF, carregue o arquivo air.swf no mesmo domínio de aplicativo do seu arquivo SWF. O código a seguir mostra um exemplo de como carregar o arquivo air.swf no domínio do aplicativo do arquivo SWF que está sendo carregado: var airSWF:Object; // This is the reference to the main class of air.swf var airSWFLoader:Loader = new Loader(); // Used to load the SWF var loaderContext:LoaderContext = new LoaderContext(); // Used to set the application domain loaderContext.applicationDomain = ApplicationDomain.currentDomain; airSWFLoader.contentLoaderInfo.addEventListener(Event.INIT, onInit); airSWFLoader.load(new URLRequest("http://airdownload.adobe.com/air/browserapi/air.swf"), loaderContext); function onInit(e:Event):void { airSWF = e.target.content; } Depois que o arquivo air.swf for carregado (quando o objeto contentLoaderInfo do objeto Loader despachar o evento init), você poderá chamar qualquer uma das APIs do air.swf. Essas APIs são descritas nestas seções: • “Verificar se o tempo de execução está instalado” na página 317 • “Verificar por uma página da Web se um aplicativo do AIR está instalado” na página 318 • “Instalação de um aplicativo do AIR do navegador” na página 319 • “Inicialização de um aplicativo do AIR instalado do navegador” na página 320 Nota: O arquivo badge.swf, fornecido com o SDK do AIR, carrega automaticamente o arquivo air.swf. Consulte “Usando o arquivo badge.swf para instalar um aplicativo do AIR” na página 314. As instruções desta seção se aplicam à criação do seu próprio arquivo do SWF que carrega o arquivo air.swf. Verificar se o tempo de execução está instalado Um arquivo SWF pode verificar se o tempo de execução está instalado chamando o método getStatus() no arquivo air.swf carregado de http://airdownload.adobe.com/air/browserapi/air.swf. Para obter detalhes, consulte “Carregar o arquivo air.swf” na página 317. Depois que o arquivo air.swf for carregado, o arquivo SWF poderá chamar o método getStatus() do arquivo air.swf como a seguir: var status:String = airSWF.getStatus(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 318 Distribuição, instalação e execução de aplicativos do AIR O método getStatus() retorna um dos seguintes valores de seqüências de caracteres, com base no status do tempo de execução no computador: Valor de string Descrição "available" O tempo de execução pode ser instalado nesse computador, mas não está instalado no momento. "unavailable" O tempo de execução não pode ser instalado neste computador. "installed" O tempo de execução está instalado nesse computador. O método getStatus() lança um erro se a versão necessária do Flash Player (versão 9 atualização 3 ou posterior no Windows e Mac OS ou versão 10 no Linux) não estiver instalada no navegador. Verificar por uma página da Web se um aplicativo do AIR está instalado Um arquivo SWF pode verificar se um aplicativo do AIR (com uma ID de aplicativo e uma ID de editor correspondentes) está instalado chamando o método getApplicationVersion() no arquivo air.swf carregado de http://airdownload.adobe.com/air/browserapi/air.swf. Para obter detalhes, consulte “Carregar o arquivo air.swf” na página 317. Depois que o arquivo air.swf for carregado, o arquivo SWF poderá chamar o método getApplicationVersion() do arquivo air.swf como a seguir: var appID:String = "com.example.air.myTestApplication"; var pubID:String = "02D88EEED35F84C264A183921344EEA353A629FD.1"; airSWF.getApplicationVersion(appID, pubID, versionDetectCallback); function versionDetectCallback(version:String):void { if (version == null) { trace("Not installed."); // Take appropriate actions. For instance, present the user with // an option to install the application. } else { trace("Version", version, "installed."); // Take appropriate actions. For instance, enable the // user interface to launch the application. } } O método getApplicationVersion() possui os seguintes parâmetros: Parâmetros Descrição appID A ID desse aplicativo. Para obter detalhes, consulte “Definição de identidade do aplicativo” na página 47. pubID A ID do editor do aplicativo. Para obter detalhes, consulte “Sobre identificadores do editor do AIR” na página 322. retorno de chamada Uma função de retorno de chamada para servir como a função do manipulador. O método getApplicationVersion() opera de modo assíncrono e ao detectar essa versão instalada (ou a falta de uma versão instalada), esse método de retorno de chamada é invocado. A definição do método de retorno de chamada deve incluir um parâmetro, uma seqüência de caracteres, definida para a seqüência de caracteres da versão do aplicativo instalado. Se o aplicativo não for instalado, um valor de nulo será transmitido à função, como ilustrado no exemplo de código anterior. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 319 Distribuição, instalação e execução de aplicativos do AIR O método getApplicationVersion() lança um erro se a versão necessária do Flash Player (versão 9 atualização 3 ou posterior no Windows e Mac OS ou versão 10 no Linux) não estiver instalada no navegador. Instalação de um aplicativo do AIR do navegador Um arquivo SWF pode instalar um aplicativo do AIR chamando o método installApplication() no arquivo air.swf carregado de http://airdownload.adobe.com/air/browserapi/air.swf. Para obter detalhes, consulte “Carregar o arquivo air.swf” na página 317. Depois que o arquivo air.swf for carregado, o arquivo SWF poderá chamar o método installApplication() do arquivo air.swf como no código a seguir: var url:String = "http://www.example.com/myApplication.air"; var runtimeVersion:String = "1.0"; var arguments:Array = ["launchFromBrowser"]; // Optional airSWF.installApplication(url, runtimeVersion, arguments); O método installApplication() instala o aplicativo especificado na máquina do usuário. Esse método possui os seguintes parâmetros: Parâmetro Descrição url Uma seqüência de caracteres que define a URL do arquivo do AIR a instalar. Você deve usar um caminho de URL absoluta, e não relativa. runtimeVersion Uma seqüência de caracteres que indica a versão do tempo de execução (como "1.0") exigida pelo aplicativo a ser instalado. arguments Uma matriz de argumentos a serem transmitidos ao aplicativo se ele for iniciado na instalação. Somente caracteres alfanuméricos são reconhecidos nos argumentos. Se for necessário passar outros valores, considere o uso de um esquema de codificação. O aplicativo é iniciado na instalação se o elemento allowBrowserInvocation é definido como true no arquivo do descritor do aplicativo. (Para obter mais informações sobre o arquivo do descritor do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44.) Se o aplicativo for iniciado como resultado de uma instalação direta do navegador (com o usuário optando por iniciar na instalação), o objeto NativeApplication do aplicativo despacha um objeto BrowserInvokeEvent apenas se argumentos tiverem sido transmitidos. Para obter detalhes, consulte “Inicialização de um aplicativo do AIR instalado do navegador” na página 320. O método installApplication() pode operar apenas quando chamado no manipulador de eventos para um evento do usuário, como um clique do mouse. O método installApplication() lança um erro se a versão necessária do Flash Player (versão 9 atualização 3 ou posterior no Windows e Mac OS ou versão 10 no Linux) não estiver instalada no navegador. No Mac OS, para instalar uma versão atualizada de um aplicativo, o usuário precisa ter privilégios adequados do sistema para instalar no diretório do aplicativo (e privilégios administrativos se o aplicativo atualizar o tempo de execução). No Windows, o usuário deve ter privilégios administrativos. Você também pode chamar o método getApplicationVersion() do arquivo air.swf para verificar se um aplicativo já está instalado. Você pode chamar esse método antes que o processo de instalação do aplicativo seja iniciado ou após a instalação ser iniciada. Para obter detalhes, consulte “Verificar por uma página da Web se um aplicativo do AIR está instalado” na página 318. Depois que o aplicativo estiver em execução, ele pode se comunicar com o conteúdo do SWF no navegador usando a classe LocalConnection. Para obter detalhes, consulte “Comunicação entre aplicativos” na página 311. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 320 Distribuição, instalação e execução de aplicativos do AIR Inicialização de um aplicativo do AIR instalado do navegador Para usar o recurso de invocação do navegador (permitindo que ele seja iniciado do navegador), o arquivo do descritor do aplicativo de destino deve incluir a seguinte configuração: <allowBrowserInvocation>true</allowBrowserInvocation> Para obter mais informações sobre o arquivo do descritor do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44. Um arquivo SWF no navegador pode iniciar um aplicativo do AIR chamando o método launchApplication() no arquivo air.swf carregado de http://airdownload.adobe.com/air/browserapi/air.swf. Para obter detalhes, consulte “Carregar o arquivo air.swf” na página 317. Depois que o arquivo air.swf for carregado, o arquivo SWF poderá chamar o método launchApplication() do arquivo air.swf como no código a seguir: var appID:String = "com.example.air.myTestApplication"; var pubID:String = "02D88EEED35F84C264A183921344EEA353A629FD.1"; var arguments:Array = ["launchFromBrowser"]; // Optional airSWF.launchApplication(appID, pubID, arguments); O método launchApplication() é definido no nível superior do arquivo air.swf (carregado no domínio do aplicativo do arquivo SWF da interface do usuário). Chamar esse método faz com que o AIR inicie o aplicativo especificado (se ele for instalado e a invocação do navegador for permitida, pela configuração allowBrowserInvocation no arquivo do descritor do aplicativo). O método tem os seguintes parâmetros: Parâmetro Descrição appID A ID do aplicativo a ser iniciado. Para obter detalhes, consulte “Definição de identidade do aplicativo” na página 47. pubID A ID do editor do aplicativo a ser iniciado. Para obter detalhes, consulte “Sobre identificadores do editor do AIR” na página 322. arguments Uma matriz de argumentos para transmitir ao aplicativo. O objeto NativeApplication do aplicativo despacha um evento BrowserInvokeEvent que possui uma propriedade de argumentos definida para essa matriz. Somente caracteres alfanuméricos são reconhecidos nos argumentos. Se for necessário passar outros valores, considere o uso de um esquema de codificação. O método launchApplication() pode operar apenas quando chamado no manipulador de eventos para um evento do usuário, como um clique do mouse. O método launchApplication() lança um erro se a versão necessária do Flash Player (versão 9 atualização 3 ou posterior no Windows e Mac OS ou versão 10 no Linux) não estiver instalada no navegador. Se o elemento allowBrowserInvocation for definido como false no arquivo do descritor do aplicativo, chamar o método launchApplication() não terá efeito. Antes de apresentar a interface do usuário para iniciar o aplicativo, você pode desejar chamar o método getApplicationVersion() no arquivo air.swf. Para obter detalhes, consulte “Verificar por uma página da Web se um aplicativo do AIR está instalado” na página 318. Quando o aplicativo é invocado pelo recurso de invocação do navegador, o objeto NativeApplication do aplicativo despacha um objeto BrowserInvokeEvent. Para obter detalhes, consulte “Invocação do navegador” na página 294. Se você usa o recurso de invocação do navegador, certifique-se de considerar implicações de segurança, descritas em “Invocação do navegador” na página 294. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 321 Distribuição, instalação e execução de aplicativos do AIR Depois que o aplicativo estiver em execução, ele pode se comunicar com o conteúdo do SWF no navegador usando a classe LocalConnection. Para obter detalhes, consulte “Comunicação entre aplicativos” na página 311. Implantação empresarial Os administradores de TI podem instalar o tempo de execução do Adobe AIR e aplicativos do AIR de modo silencioso usando ferramentas de implantação de área de trabalho padrão. Os administradores de TI podem fazer o seguinte: • Instalar silenciosamente o tempo de execução do Adobe AIR usando ferramentas como Microsoft SMS, IBM Tivoli, ou qualquer ferramenta de implantação que permita instalações silenciosas que usem um inicializador • Instalar silenciosamente o aplicativo do AIR usando as mesmas ferramentas usadas para implantar o tempo de execução Para obter mais informações, consulte o Guia do administrador do Adobe AIR (http://www.adobe.com/go/learn_air_admin_guide_en). Assinatura digital de um arquivo do AIR Assinar digitalmente seus arquivos de instalação do AIR com um certificado emitido por uma autoridade de certificação reconhecida (CA) fornece uma garantia significativa aos seus usuários de que o aplicativo que estão instalando não foi alterado de modo acidental ou mal-intencionado e o identifica como o signatário (editor). O AIR exibe o nome do editor durante a instalação quando o aplicativo do AIR tiver sido assinado com um certificado confiável ou que esteja vinculado a um certificado confiável no computador de instalação. Caso contrário, o nome do editor será exibido como “Desconhecido”. Importante: Uma entidade mal-intencionada poderia falsificar um arquivo do AIR com sua identidade se ela, de alguma forma, obtiver seu arquivo de armazenamento de chaves de assinatura ou descobrir sua chave privada. Informações sobre certificados de assinatura de código As garantias de segurança, limitações e obrigações legais que envolvem o uso de certificados de assinatura de código são descritas nas Declarações de Práticas de Certificação (CPS) e nos contratos de assinatura publicados pela autoridade de certificação emissora. Para obter mais informações sobre os contratos das autoridades de certificação que emitem atualmente certificados de assinatura de código do AIR, consulte: ChosenSecurity (http://www.chosensecurity.com/products/tc_publisher_id_adobe_air.htm) http://www.chosensecurity.com/resource_center/repository.htm (http://www.chosensecurity.com/resource_center/repository.htm) GlobalSign (http://www.globalsign.com/developer/code-signing-certificate/index.htm) CPS da GlobalSign (http://www.globalsign.com/repository/index.htm) CPS da Thawte (http://www.thawte.com/cps/index.html) Contrato de desenvolvedor de assinatura de código da Thawte (http://www.thawte.com/ssl-digital-certificates/freeguides-whitepapers/pdf/develcertsign.pdf) VeriSign CPS (http://www.verisign.com/repository/CPS/) Contrato de assinante do VeriSign (https://www.verisign.com/repository/subscriber/SUBAGR.html) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 322 Distribuição, instalação e execução de aplicativos do AIR Sobre a assinatura de código do AIR Quando um arquivo do AIR é assinado, uma assinatura digital é incluída no arquivo de instalação. A assinatura inclui uma compilação do pacote, usada para verificar se o arquivo do AIR não foi alterado desde que foi assinado e se ele inclui informações sobre o certificado de assinatura, usado para verificar a identidade do editor. O AIR usa a infra-estrutura de chave pública (PKI) suportada pelo armazenamento de certificados do sistema operacional para estabelecer se um certificado pode ser confiável. O computador no qual um aplicativo do AIR está instalado deve confiar diretamente no certificado usado para assinar o aplicativo do AIR ou deve confiar em uma cadeia de certificados que vincula o certificado a uma autoridade de certificação confiável para que as informações do editor sejam verificadas. Se um arquivo do AIR for assinado com um certificado que não vincula a nenhum dos certificados raiz confiáveis (e normalmente isso inclui todos os certificados auto-assinados), as informações do editor não podem ser verificadas. Embora o AIR possa determinar que o pacote do AIR não foi alterado desde que ele foi assinado, não há como saber quem realmente criou e assinou o arquivo. Nota: Um usuário pode optar por confiar em um certificado auto-assinado e, em seguida, qualquer aplicativo do AIR assinado com o certificado exibirá o valor do campo de nome comum no certificado como o nome do editor. O AIR não fornece nenhum meio de um usuário designar um certificado como confiável. O certificado (não incluindo a chave privada) deve ser fornecido ao usuário separadamente e o usuário deve usar um dos mecanismos fornecidos pelo sistema operacional ou uma ferramenta apropriada para importar o certificado no local apropriado no armazenamento de certificados do sistema. Sobre identificadores do editor do AIR Como parte do processo de criar um arquivo do AIR, a ferramenta para desenvolvedores do AIR (ADT) gera uma ID do editor. Esse é um identificador único para o certificado usado para criar o arquivo do AIR. Se você reutilizar o mesmo certificado para vários aplicativos do AIR, eles terão a mesma ID do editor. A ID do editor é usada para identificar o aplicativo do AIR em comunicação LocalConnection (consulte “Comunicação entre aplicativos” na página 311). Você pode identificar a ID do editor de um aplicativo instalado lendo a propriedade NativeApplication.nativeApplication.publisherID. Os campos a seguir são usados para computar a ID do editor: Name, CommonName, Surname, GivenName, Initials, GenerationQualifier, DNQualifier, CountryName, localityName, StateOrProvinceName, OrganizationName, OrganizationalUnitName, Title, Email, SerialNumber, DomainComponent, Pseudonym, BusinessCategory, StreetAddress, PostalCode, PostalAddress, DateOfBirth, PlaceOfBirth, Gender, CountryOfCitizenship, CountryOfResidence e NameAtBirth. Se você renovar um certificado emitido por uma autoridade de certificação ou gerar novamente um certificado auto-assinado, esses campos deverão ser iguais para a ID do editor permanecer a mesma. Além disso, o certificado raiz de um certificado emitido por uma CA e a chave pública de um certificado autoassinado devem ser os mesmos. Sobre formatos de certificados As ferramentas de assinatura do AIR aceitam qualquer armazenamento de chave acessível pela JCA (arquitetura de criptografia Java). Isso inclui armazenamentos de chaves baseados em arquivos como arquivos de formatos PKCS12 (que normalmente usam uma extensão de arquivo .pfx ou .p12), arquivos .keystore Java, armazenamentos de chaves de hardware PKCS11 e armazenamentos de chaves de sistema. Os formatos de armazenamento de chave que o ADT pode acessar dependem da versão e configuração do tempo de execução Java usado para executar o ADT. Acessar alguns tipos de armazenamento de chave, como tokens de hardware PKCS11, pode exigir a instalação e configuração de drivers de software adicionais e plug-ins de JCA. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 323 Distribuição, instalação e execução de aplicativos do AIR Para assinar arquivos do AIR, você pode usar a maioria dos certificados de assinatura de código existentes ou obter um novo, emitido expressamente para assinar aplicativos do AIR. Por exemplo, qualquer um dos seguintes tipos de certificado da VeriSign, Thawte, GlobalSign ou ChosenSecurity podem ser usados: • ChosenSecurity • ID de Editor TC para Adobe AIR • GlobalSign • Certificado de assinatura de código ObjectSign • Thawte: • Certificado do desenvolvedor do AIR • Certificado do desenvolvedor Apple • Certificado do desenvolvedor JavaSoft • Certificado Microsoft Authenticode • VeriSign: • ID digital do Adobe AIR • ID digital Microsoft Authenticode • ID digital de assinatura Sun Java Nota: O certificado deve ser criado para assinatura de código. Você não pode usar um SSL ou outro tipo de certificado para assinar arquivos do AIR. Carimbos de data/hora Quando você assina um arquivo do AIR, a ferramenta de empacotamento consulta o servidor de uma autoridade de carimbo de data/hora para obter uma data e hora da assinatura independentemente verificáveis. O carimbo de data/hora está incorporado no arquivo do AIR. Desde que o certificado de assinatura seja válido no momento da assinatura, o arquivo do AIR poderá ser instalado, mesmo depois que o certificado expirar. Por outro lado, se nenhum carimbo de data/hora for obtido, o arquivo do AIR não poderá mais ser instalado quando o certificado expirar ou for revogado. Por padrão, as ferramentas de empacotamento do AIR obtêm um carimbo de data/hora. No entanto, para permitir que aplicativos sejam empacotados quando o serviço de carimbo de data/hora estiver indisponível, você pode desativar o recurso de carimbo de data/hora. A Adobe recomenda que todos os arquivos do AIR distribuídos publicamente incluam um carimbo de data/hora. A autoridade padrão de carimbo de data/hora usada pelas ferramentas de empacotamento do AIR é Geotrust. Obtenção de um certificado Para obter um certificado, você normalmente visitaria o site da autoridade de certificação na Web e completaria o processo de obtenção da empresa. As ferramentas usadas para produzir o arquivo de armazenamento de chave necessário pelas ferramentas do AIR dependem do tipo de certificado adquirido, de como o certificado é armazenado no computador recebedor e, em alguns casos, o navegador usado para obter o certificado. Por exemplo, para obter e exportar um certificado do Adobe Developer do Thawte, você deve usar o Mozilla Firefox. O certificado pode então ser exportado como um arquivo .12 diretamente da interface do usuário do Firefox. Você pode gerar um certificado auto-assinado usando a ferramenta para desenvolvedores do AIR (ADT) usada para empacotar arquivos de instalação do AIR. Algumas ferramentas de terceiros também podem ser usadas. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 324 Distribuição, instalação e execução de aplicativos do AIR Para obter instruções como gerar um certificado auto-assinado, bem como instruções sobre como assinar um arquivo do AIR, consulte “Empacotamento de um arquivo de instalação do AIR usando o ADT (ferramenta para desenvolvedores do AIR)” na página 357. Você também pode exportar e assinar arquivos do AIR usando o Flex Builder, Dreamweaver e a atualização do AIR para o Flash. O exemplo a seguir descreve como obter um Certificado de desenvolvedor do AIR da autoridade de certificação Thawte e prepará-lo para o uso com o ADT. Exemplo: Obtenção de um certificado do desenvolvedor do AIR da Thawte Nota: Este exemplo ilustra apenas uma das várias maneiras de se obter e preparar um certificado de assinatura do código para o uso. Cada autoridade de certificação tem suas próprias políticas e procedimentos. Para adquirir um certificado do desenvolvedor do AIR, o site da Thawte na Web requer que você use o navegador Mozilla Firefox. A chave privada para o certificado é armazenada no armazenamento de chave do navegador. Verifique se o armazenamento de chave do Firefox é protegido por uma senha mestre e se o computador em si é fisicamente seguro. (Você pode exportar e remover o certificado e a chave privada do armazenamento de chave do navegador quando o processo de obtenção estiver concluído.) Como parte do processo de inscrição do certificado, é gerado um par de chave privada/pública. A chave privada é armazenada automaticamente no armazenamento de chave do Firefox. Você deve usar o mesmo computador e navegador para solicitar e recuperar o certificado do site da Thawte na Web. 1 Visite o site da Thawte na Web e navegue até Página de produtos para certificados de assinatura de código. 2 Da lista de certificados de assinatura de código, selecione o certificado do desenvolvedor do Adobe AIR. 3 Complete o processo de inscrição de três etapas. Você precisa fornecer informações organizacionais e de contato. A Thawte executa então seu processo de verificação de identidade e pode solicitar informações adicionais. Após a conclusão da verificação, a Thawte enviará um e-mail com instruções sobre como recuperar o certificado. Nota: informações adicionais sobre o tipo de documentação necessária podem ser encontradas aqui: https://www.thawte.com/ssl-digital-certificates/free-guides-whitepapers/pdf/enroll_codesign_eng.pdf. 4 Recupere o certificado emitido do site da Thawte. O certificado é salvo automaticamente no armazenamento de chave do Firefox. 5 Exporte um arquivo de armazenamento de chave contendo a chave privada e o certificado do armazenamento de chave do Firefox usando as seguintes etapas: Nota: Ao exportar a chave privada/certificado do Firefox, ele é exportado em um formato de .p12 (pfx) que o ADT, Flex, Flash e o Dreamweaver podem usar. a Abra a caixa de diálogo do gerenciador de certificados do Firefox: b No Windows: abra Tools (Ferramentas) -> Options (Opções) -> Advanced (Avançadas) -> Encryption (Criptografia) -> View Certificates (Exibir certificados) c No Mac OS: abra Firefox (Firefox) -> Preferences (Preferências) -> Advanced (Avançadas) -> Encryption (Criptografia) -> View Certificates (Exibir certificados) d No Linux: abra Edit (Editar) -> Preferences (Preferências) -> Advanced (Avançadas) -> Encryption (Criptografia) -> View Certificates (Exibir certificados) e Selecione o certificado de assinatura do código do Adobe AIR da lista de certificados e clique no botão Backup. f Digite um nome de arquivo e a localização para a qual exportar o arquivo de armazenamento de chave e clique em Save (Salvar). g Se estiver usando a senha mestre do Firefox, será solicitado que você digite sua senha para o dispositivo de segurança do software para exportar o arquivo. (Essa senha é usada apenas pelo Firefox.) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 325 Distribuição, instalação e execução de aplicativos do AIR h Na caixa de diálogo Choose a Certificate Backup Password (Escolha uma senha de backup de certificado), crie uma senha para o arquivo de armazenamento de chave. Importante: Essa senha protege o arquivo de armazenamento de chave e é necessária quando o arquivo é usado para assinar aplicativos do AIR. Uma senha segura deve ser escolhida. i Clique em OK. Você deve receber uma mensagem de senha de backup bem-sucedida. O arquivo de armazenamento de chave contendo a chave privada e o certificado é salvo com uma extensão de arquivo .p12 (no formato PKCS12) 6 Use o arquivo de armazenamento de chave exportado com o ADT, Flex Builder, Flash ou Dreamweaver. A senha criada para o arquivo é necessária sempre que um aplicativo do AIR é assinado. Importante: A chave privada e o certificado ainda são armazenados no armazenamento de chave do Firefox. Enquanto isso permite que você exporte uma cópia adicional do arquivo de certificado, também fornece outro ponto de acesso que deve ser protegido para manter a segurança do seu certificado e da chave privada. Alteração de certificados Em algumas circunstâncias, você pode precisar alterar o certificado usado para assinar seu aplicativo do AIR. Tais circunstâncias incluem: • Atualização de um certificado auto-assinado para um certificado emitido por uma autoridade de certificação • Alteração de um certificado auto-assinado prestes a expirar para outro • Alterar um certificado comercial para outro, por exemplo, quando sua identidade corporativa for alterada Como o certificado de assinatura é um dos elementos que determina a identidade de um aplicativo do AIR, você não pode simplesmente assinar uma atualização para o seu aplicativo com um certificado diferente. Para que o AIR reconheça um arquivo do AIR como uma atualização, você deve assinar o arquivo original e qualquer arquivo atualizado do AIR com o mesmo certificado. Caso contrário, o AIR instala o novo arquivo do AIR como um aplicativo separado em vez de atualizar a instalação existente. No AIR 1.1, você pode alterar o certificado de assinatura de um aplicativo usando uma assinatura de migração. Uma assinatura de migração é uma segunda assinatura aplicada ao arquivo de atualização do AIR. A assinatura de migração usa o certificado original, que estabelece que o signatário é o editor original do aplicativo. Importante: O certificado deve ser alterado antes que o certificado original expire ou seja revogado. Se você não criar uma atualização assinada com uma assinatura de migração antes que seu certificado expire, os usuários terão que desinstalar sua versão existente do seu aplicativo antes de instalar qualquer atualização. Certificados emitidos comercialmente podem normalmente ser renovados para evitar a expiração. Certificados auto-assinados não podem ser renovados. Para alterar os certificados: 1 Crie uma atualização para o seu aplicativo 2 Empacote e assine o arquivo de atualização do AIR com o novo certificado 3 Assine o arquivo do AIR novamente com o certificado original (usando o comando -migrate do ADT) O procedimento para aplicar uma assinatura de migração é descrito em “Assinatura de um arquivo do AIR para alterar o certificado do aplicativo” na página 367. Quando o arquivo do AIR atualizado é instalado, a identidade do aplicativo é alterada. Essa alteração de identidade possui as seguintes repercussões: • A ID do editor do aplicativo é alterada para corresponder ao novo certificado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 326 Distribuição, instalação e execução de aplicativos do AIR • A nova versão do aplicativo não pode acessar dados no armazenamento local criptografado existente. • O local do diretório de armazenamento do aplicativo é alterado. Os dados no local antigo não são copiados para o novo diretório. (Mas o novo aplicativo pode localizar o diretório original com base na ID do editor antigo). • O aplicativo não pode mais abrir conexões locais usando a ID do editor antigo. • Se um usuário reinstalar um arquivo do AIR de pré-migração, o AIR o instalará como um aplicativo separado usando a ID do editor original. É de responsabilidade do seu aplicativo migrar qualquer dado entre a versão original e a nova do aplicativo. Para migrar dados no ELS (Armazenamento de local criptografado), você deve exportar os dados antes que a alteração no certificado ocorra. É impossível para a nova versão do seu aplicativo ler o ELS da versão antiga. (Muitas vezes, é mais fácil apenas recriar os dados do que migrá-lo.) Você deve continuar aplicando a assinatura de migração a quantas atualizações subseqüentes forem possíveis. Caso contrário, os usuários que ainda não atualizaram do original devem instalar uma versão de migração intermediária ou desinstalar sua versão atual antes que possam instalar sua atualização mais recente. Finalmente, é claro, o certificado original irá expirar e você não poderá mais aplicar uma assinatura de migração. (No entanto, a menos que você desabilite o carimbo de data/hora, os arquivos do AIR assinados anteriormente com uma assinatura de migração permanecerão válidos. A assinatura de migração é carimbada com data e hora para permitir que o AIR aceite a assinatura mesmo depois que o certificado expirar.) Um arquivo do AIR com uma assinatura de migração é, em outros aspectos, um arquivo do AIR normal. Se o aplicativo é instalado em um sistema sem a versão original, o AIR instala a nova versão da maneira normal. Nota: Você não precisa normalmente migrar o certificado quando renovar um certificado emitido comercialmente. Um certificado renovado retém a mesma identidade do editor do original, a menos que o nome distinto tenha sido alterado. Para obter uma lista completa dos atributos do certificado usados para determinar o nome distinto, consulte “Sobre identificadores do editor do AIR” na página 322. Terminologia Esta seção fornece um glossário de um pouco da terminologia principal que você deve entender ao tomar decisões sobre como assinar seu aplicativo para distribuição pública. Termo Descrição Autoridade de certificação (CA) Uma entidade em uma rede de infra-estrutura de chave pública que serve como um terceiro confiável e, por último, certifica a identidade do proprietário de uma chave pública. Uma CA normalmente emite certificados digitais, assinados por sua própria chave privada, para atestar que ela verificou a identidade do proprietário do certificado. Declaração de Prática de Certificação (CPS) Apresenta as práticas e políticas da autoridade de certificação em emitir e verificar certificados. A CPS é parte do contrato entre a CA e seus assinantes e terceiros. Ela também resume as políticas para verificação de identidade e o nível de garantias oferecidas pelos certificados que elas fornecem. Lista de revogação de certificado (CRL) Uma lista de certificados emitidos que foram revogados e nos quais não se deve mais confiar. O AIR verifica o CRL no momento em que um aplicativo do AIR é assinado e, se nenhum carimbo de data/hora estiver presente, novamente quando o aplicativo for instalado. Cadeia de certificados Uma cadeia de certificados é uma seqüência de certificados na qual cada certificado da cadeia foi assinado pelo certificado seguinte. Certificado digital Um documento digital que contém informações sobre a identidade do proprietário, a chave pública do proprietário e a identidade do certificado em si. Um certificado emitido por uma autoridade de certificação é em si assinado por um certificado que pertence à CA emissora. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 327 Distribuição, instalação e execução de aplicativos do AIR Termo Descrição Assinatura digital Uma mensagem criptografada ou uma compilação que pode apenas ser descriptografada com metade da chave pública de um par de chave pública-privada. Em uma PKI, uma assinatura digital contém um ou mais certificados digitais rastreáveis, por último, para a autoridade de certificação. Uma assinatura digital pode ser usada para validar que uma mensagem (ou arquivo do computador) não foi alterada desde que ela foi assinada (nos limites da garantia fornecida pelo algoritmo criptográfico usado) e, supondo que alguém confia na autoridade de certificação emissora, a identidade do signatário. Armazenamento de chave Um banco de dados contendo certificados digitais e, em alguns casos, as chaves privadas relacionadas. JCA (arquitetura de criptografia Java) Uma arquitetura extensível para gerenciar e acessar armazenamentos de chaves. Consulte o Guia de referência da arquitetura de criptografia Java para obter mais informações. PKCS n º 11 O padrão de interface de token criptográfico da RSA Laboratories. Um armazenamento de chave baseado em token de hardware. PKCS n º 12 O padrão de sintaxe do Exchange de informações pessoais da RSA Laboratories. Um armazenamento de chave baseado em arquivo que normalmente contém uma chave privada e seu certificado digital associado. Chave privada A metade privada de um sistema criptográfico assimétrico de chave pública-privada de duas partes. A chave privada deve ser mantida em segredo e nunca deve ser transmitida pela rede. Mensagens assinadas digitalmente são criptografadas com a chave privada pelo signatário. Chave pública A metade pública de um sistema criptográfico assimétrico de chave pública-privada de duas partes. A chave pública está abertamente disponível e é usada para descriptografar mensagens criptografadas com a chave privada. Infra-estrutura de chave pública (PKI) Um sistema de confiança no qual as autoridades de certificação atestam para a identidade dos proprietários de chaves públicas. Clientes da rede confiam nos certificados digitais emitidos por uma CA confiável para verificar a identidade do signatário de uma mensagem digital (ou arquivo). Carimbo de data/hora Um dado assinado digitalmente contendo a data e hora em que um evento ocorreu. O ADT pode incluir um carimbo de data/hora de um servidor compatível com hora RFC 3161 em um pacote do AIR. Quando presente, o AIR usa o carimbo de data/hora para estabelecer a validade de um certificado no momento da assinatura. Isso permite que um aplicativo do AIR seja instalado após seu certificado de assinatura ter expirado. Autoridade de carimbo de data/hora Uma autoridade que emite carimbos de data/hora. Para ser reconhecido pelo AIR, o carimbo de data/hora deve estar em conformidade com RFC 3161 e a assinatura de carimbo de data/hora deve ser vinculada a um certificado raiz confiável na máquina de instalação. 328 Capítulo 33: Atualização de aplicativos do AIR Os usuários podem instalar ou atualizar um aplicativo do AIR clicando duas vezes no arquivo AIR no computador ou a partir do navegador (usando o recurso de instalação direta). O aplicativo instalador do Adobe® AIR™ gerencia a instalação, alertando o usuário se ele estiver atualizando um aplicativo já existente. (Consulte “Distribuição, instalação e execução de aplicativos do AIR” na página 312.) No entanto, também é possível que um aplicativo instalado se atualize automaticamente para uma nova versão usando a classe Updater. (Um aplicativo instalado pode detectar que uma nova versão está disponível para download e instalação.) A classe Updater inclui um método update() que permite apontar para um arquivo do AIR no computador do usuário e atualizar para essa versão. As IDs do aplicativo e do editor de um arquivo do AIR de atualização devem corresponder às do aplicativo a ser atualizado. A ID do editor é derivada do certificado de autenticação, o que significa que a atualização e o aplicativo a ser atualizado devem ser assinados com o mesmo certificado. A partir do AIR 1.1, é possível migrar um aplicativo para usar um novo certificado de autenticação de código. A migração de um aplicativo para usar uma nova assinatura envolve assinar o arquivo do AIR de atualização com os certificados novo e original. A migração de certificado é um processo unidirecional. Após a migração, somente os arquivos do AIR assinados com o novo certificado (ou com ambos) serão reconhecidos como atualizações de uma instalação existente. Gerenciar a atualização de aplicativos pode ser complicado. O AIR 1.5 inclui a nova estrutura de atualização para aplicativos do Adobe® AIR™. Essa estrutura fornece APIs para auxiliar os desenvolvedores a fornecer bons recursos de atualização em aplicativos do AIR. Você pode usar a migração de certificado para mudar de um certificado auto-assinado para um certificado comercial de autenticação de código ou de um certificado auto-assinado ou comercial para outro. Caso você não migre o certificado, os usuários existentes deverão remover a versão atual do seu aplicativo antes de instalar a nova. Para obter mais informações, consulte “Alteração de certificados” na página 325. Sobre atualização de aplicativos A classe Updater (no pacote flash.desktop) inclui um método, update(), que você pode usar para atualizar o aplicativo que está sendo executado com outra versão. Por exemplo, se o usuário tem uma versão do arquivo do AIR ("Sample_App_v2.air") localizada na área de trabalho, o seguinte código atualiza o aplicativo: var updater:Updater = new Updater(); var airFile:File = File.desktopDirectory.resolvePath("Sample_App_v2.air"); var version:String = "2.01"; updater.update(airFile, version); Antes de um aplicativo usar a classe Updater, o usuário ou o aplicativo deve baixar a versão atualizada do arquivo do AIR no computador. Para obter mais informações, consulte “Download de um arquivo do AIR no computador do usuário” na página 330. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 329 Atualização de aplicativos do AIR Resultados de chamar o método Updater.update() Quando um aplicativo no tempo de execução chama o método update(), o tempo de execução fecha o aplicativo e tenta instalar a nova versão do arquivo do AIR. O tempo de execução verifica se a ID do aplicativo e a ID do editor especificadas no arquivo do AIR correspondem às IDs do aplicativo e do editor do aplicativo que está chamando o método update(). (Para obter informações sobre a ID do aplicativo e a ID do editor, consulte “Configuração de propriedades do aplicativo do AIR” na página 44.) Ele também verifica se a string de versão corresponde à string version passada para o método update(). Se a instalação for concluída com êxito, o tempo de execução abrirá a nova versão do aplicativo. Do contrário (se a instalação não for concluída), ele reabrirá a versão existente (pré-instalação) do aplicativo. No Mac OS, para instalar uma versão atualizada de um aplicativo, o usuário deve ter privilégios adequados do sistema para instalar no diretório do aplicativo. No Windows e no Linux, um usuário precisa de privilégios administrativos. Se a versão atualizada do aplicativo exigir uma versão atualizada do tempo de execução, a nova versão do tempo de execução será instalada. Para atualizar o tempo de execução, o usuário deve ter privilégios administrativos no computador. Durante o teste de um aplicativo usando o ADL, se o método update() for chamado, será gerada uma exceção do tempo de execução. Sobre a string de versão A string especificada como o parâmetro version do método update() deve corresponder à string no atributo version do principal elemento application do arquivo de descrição do aplicativo referente ao arquivo do AIR a ser instalado. É necessário especificar o parâmetro version por motivo de segurança. Ao exigir que o aplicativo verifique o número da versão no arquivo do AIR, o aplicativo não instalará inadvertidamente uma versão mais antiga, que pode conter uma vulnerabilidade de segurança corrigida no aplicativo que está instalado. O aplicativo também deve verificar a string de versão no arquivo do AIR com a string de versão no aplicativo instalado para impedir ataques de downgrade. A string de versão pode ter qualquer formato. Por exemplo, pode ser "2.01" ou "versão 2". A decisão quanto ao formato dessa string fica a seu critério, que é o desenvolvedor do aplicativo. O tempo de execução não valida a string de versão; o código do aplicativo deve fazer isso antes de atualizar o aplicativo. Se um aplicativo do Adobe AIR baixa um arquivo do AIR pela web, é recomendável ter um mecanismo através do qual o serviço da web possa notificar o aplicativo sobre a versão que está sendo baixada. O aplicativo poderá então usar essa string como o parâmetro version do método update(). Se o arquivo do AIR for obtido por algum outro meio, no qual a versão do arquivo é desconhecida, o aplicativo do AIR poderá examiná-lo para determinar a informação de versão. (Um arquivo do AIR consiste em um arquivo compactado no formato ZIP, e o arquivo de descrição do aplicativo é o segundo registro no arquivo.) Para obter detalhes sobre o arquivo de descrição do aplicativo, consulte “Configuração de propriedades do aplicativo do AIR” na página 44. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 330 Atualização de aplicativos do AIR Apresentação de uma interface de usuário de atualização do aplicativo personalizado O AIR vem com uma interface de atualização padrão: Essa interface sempre é usada quando o usuário instala uma versão de um aplicativo em uma máquina pela primeira vez. No entanto, você pode definir sua própria interface para usá-la em ocorrências subseqüentes. Se seu aplicativo definir uma interface de atualização personalizada, especifique um elemento customUpdateUI no arquivo de descritor do aplicativo para o aplicativo instalado no momento: <customUpdateUI>true</customUpdateUI> Quando o aplicativo é instalado e o usuário abre um arquivo do AIR com uma ID de aplicativo e uma ID de editor que correspondem às do aplicativo instalado, o tempo de execução abre o aplicativo em vez no instalador de aplicativo padrão do AIR. Para obter mais informações, consulte “Fornecer uma interface de usuário personalizada para atualizações de aplicativos” na página 52. O aplicativo pode decidir, quando executado (quando o objeto NativeApplication.nativeApplication despacha um evento load), se o aplicativo deve ser atualizado (usando a classe Updater). Se ele optar pela atualização, poderá apresentar ao usuário sua própria interface de instalação (que é diferente da interface padrão que está sendo executada). Download de um arquivo do AIR no computador do usuário Para utilizar a classe Updater, primeiro o usuário ou o aplicativo deve salvar um arquivo do AIR localmente no computador do usuário. Nota: O AIR 1.5 inclui uma estrutura de atualização, que auxilia desenvolvedores no fornecimento de bons recursos de atualização em aplicativos do AIR. Usar essa estrutura pode ser bem mais fácil que usar o método update() da classe Update diretamente. Para obter detalhes, consulte “Uso da estrutura de atualização” na página 332. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 331 Atualização de aplicativos do AIR O código abaixo lê um arquivo do AIR a partir de uma URL (http://example.com/air/updates/Sample_App_v2.air) e salva o arquivo no diretório de armazenamento do aplicativo: var urlString:String = "http://example.com/air/updates/Sample_App_v2.air"; var urlReq:URLRequest = new URLRequest(urlString); var urlStream:URLStream = new URLStream(); var fileData:ByteArray = new ByteArray(); urlStream.addEventListener(Event.COMPLETE, loaded); urlStream.load(urlReq); function loaded(event:Event):void { urlStream.readBytes(fileData, 0, urlStream.bytesAvailable); writeAirFile(); } function writeAirFile():void { var file:File = File.applicationStorageDirectory.resolvePath("My App v2.air"); var fileStream:FileStream = new FileStream(); fileStream.open(file, FileMode.WRITE); fileStream.writeBytes(fileData, 0, fileData.length); fileStream.close(); trace("The AIR file is written."); } Para obter mais informações, consulte “Fluxo de trabalho de leitura e gravação de arquivos” na página 121. Verificar se um aplicativo está sendo executado pela primeira vez Depois que você atualizar um aplicativo, convém exibir para o usuário uma mensagem de "introdução" ou "boasvindas". Após a inicialização, o aplicativo verifica se está sendo executado pela primeira vez para determinar se deve exibir a mensagem. Nota: O AIR 1.5 inclui uma estrutura de atualização, que auxilia desenvolvedores no fornecimento de bons recursos de atualização em aplicativos do AIR. Essa estrutura fornece métodos fáceis para verificar se uma versão de um aplicativo está sendo executada pela primeira vez. Para obter detalhes, consulte “Uso da estrutura de atualização” na página 332. Uma forma de fazer isso é salvar um arquivo no diretório de armazenamento do aplicativo depois de inicializá-lo. Sempre que o aplicativo é inicializado, deve averiguar se esse arquivo existe. Se o arquivo não existir, isso indica que o aplicativo está sendo executado pela primeira vez para o usuário atual. Se o arquivo existir, o aplicativo já foi executado pelo menos uma vez. Se o arquivo existir e contiver um número de versão mais antigo que o atual, você saberá que o usuário está executando a nova versão pela primeira vez. Se o seu aplicativo salva dados localmente (como no diretório de armazenamento do aplicativo), convém verificar se existem dados já salvos (de versões anteriores) após a primeira execução. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 332 Atualização de aplicativos do AIR Uso da estrutura de atualização Gerenciar a atualização de aplicativos pode ser complicado. A estrutura de atualização para aplicativos AdobeAIR fornece APIs para auxiliar desenvolvedores no fornecimento de bons recursos de atualização em aplicativos do AIR. A funcionalidade na estrutura de atualização do AIR auxilia desenvolvedores a: • Verificar periodicamente atualizações com base em um intervalo ou na solicitação do usuário • Baixar arquivos do AIR (atualizações) de uma fonte da Web • Alertar o usuário na primeira execução da versão recém-instalada • Confirmar se o usuário deseja verificar atualizações • Exibir informações sobre a nova versão de atualização para o usuário • Exibir o andamento do download e as informações de erro para o usuário A estrutura de atualização do AIR fornece um exemplo de interface de usuário que seu aplicativo pode usar. Ela fornece ao usuário informações básicas e opções relacionadas às atualizações do aplicativo. Seu aplicativo também pode definir a própria interface de usuário personalizada para uso com a estrutura de atualização. A estrutura de atualização do AIR permite armazenar informações sobre a versão de atualização de um aplicativo AIR em arquivos de configuração XML simples. Para a maioria dos aplicativos, definir esses arquivos de configuração e incluir alguns códigos básicos fornece uma boa funcionalidade de atualização para o usuário final. Mesmo sem usar a estrutura de atualização, o Adobe AIR inclui uma classe Updater que os aplicativos do AIR podem usar para atualizar para novas versões. Essa classe permite que um aplicativo seja atualizado para uma versão contida em um arquivo do AIR no computador do usuário. No entanto, o gerenciamento de atualização pode envolver mais que simplesmente atualizar o aplicativo com base em um arquivo do AIR armazenado localmente. Arquivos na estrutura de atualização do AIR A estrutura de atualização do AIR inclui os seguintes diretórios: • doc — A documentação (que você está lendo agora) da estrutura de atualização do AIR. • estruturas – Esse diretório inclui arquivos SWC, para desenvolvimento em Flex – e arquivos SWF, para desenvolvimento em HTML. Para obter mais informações, consulte estas seções (imediatamente na seqüência): • “Configuração do ambiente de desenvolvimento em Flex” na página 332 • “Inclusão de arquivos de estrutura em um aplicativo do AIR baseado em HTML” na página 333 • amostras – Este diretório inclui exemplos baseados em HTML e Flex mostrando como usar a estrutura de atualização de aplicativo. Compile e teste esses arquivos, como faria em qualquer aplicativo do AIR. • modelos – Este diretório contém arquivos de exemplo do descritor de atualização (simples e localizados) e arquivos de configuração. (Para obter mais informações sobre esses arquivos, consulte Configuração do ambiente de desenvolvimento em Flex e “Exemplo básico: Uso da versão ApplicationUpdaterUI” na página 333). Configuração do ambiente de desenvolvimento em Flex O diretório frameworks/flex da estrutura de atualização inclui estes arquivos: • ApplicationUpdater.swc — Define a funcionalidade básica da biblioteca de atualização, sem qualquer interface do usuário • ApplicationUpdater_UI.swc — Define a funcionalidade básica da biblioteca de atualização, incluindo uma interface de usuário que seu aplicativo usa para exibir opções de atualização DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 333 Atualização de aplicativos do AIR Os arquivos SWC definem classes que você pode usar no desenvolvimento de Flex. Para usar a estrutura de atualização ao compilar com o Flex SDK, inclua o arquivo ApplicationUpdater.swc ou o ApplicationUpdater_UI.swc na chamada do compilador amxmlc. No exemplo a seguir, o compilador carrega o arquivo ApplicationUpdater.swc no subdiretório lib do diretório Flex SDK: amxmlc -library-path+=lib/ApplicationUpdater.swc -- myApp.mxml No exemplo a seguir, o compilador carrega o arquivo ApplicationUpdater_UI.swc no subdiretório lib do diretório Flex SDK: amxmlc -library-path+=lib/ApplicationUpdater_UI.swc -- myApp.mxml Ao desenvolver usando o construtor Flex, adicione o arquivo SWC à guia Caminho da biblioteca das configurações do caminho de criação de Flex na caixa de diálogo Propriedades. Assegure-se de copiar os arquivos SWC no diretório que você usará como referência no compilador amxmlc (usando o Flex SDK) ou Flex Builder. Inclusão de arquivos de estrutura em um aplicativo do AIR baseado em HTML O diretório frameworks/html da estrutura de atualização inclui estes arquivos: • ApplicationUpdater.swf — Define a funcionalidade básica da biblioteca de atualização, sem qualquer interface do usuário • ApplicationUpdater_UI.swf — Define a funcionalidade básica da biblioteca de atualização, incluindo uma interface de usuário que seu aplicativo usa para exibir opções de atualização O código JavaScript nos aplicativos do AIT podem usar classes definidas nos arquivos SWF. Para usar a estrutura de atualização, inclua o arquivo ApplicationUpdater.swf ou o ApplicationUpdater_UI.swf no diretório do aplicativo (ou um subdiretório). Em seguida, no arquivo HTML que usará a estrutura (em código JavaScript), inclua uma tag script que carregue o arquivo: <script src="applicationUpdater.swf" type="application/x-shockwave-flash"/> Ou use essa tag script para carregar o arquivo ApplicationUpdater_UI.swf: <script src="ApplicationUpdater_UI.swf" type="application/x-shockwave-flash"/> A API definida nesses dois arquivos é descrita no restante deste documento. Exemplo básico: Uso da versão ApplicationUpdaterUI A versão ApplicationUpdaterUI da estrutura de atualização fornece uma interface básica que pode ser facilmente usada no seu aplicativo. A seguir há um exemplo básico: Primeiro, crie um aplicativo do AIR que chame a estrutura de atualização: 1 Se seu aplicativo for um aplicativo do AIR baseado em HTML, carregue o arquivo ApplicationUpdaterUI.js: <script src="ApplicationUpdater_UI.swf" type="application/x-shockwave-flash"/> 2 Na lógica de programação do aplicativo do AIR, instancie um objeto do ApplicationUpdaterUI. No ActionScript, use o seguinte código: var appUpdater:ApplicationUpdaterUI = new ApplicationUpdaterUI(); No JavaScript, use o seguinte código: var appUpdater = new runtime.air.update.ApplicationUpdaterUI(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 334 Atualização de aplicativos do AIR Você pode adicionar esse código a uma função de inicialização executada quando o aplicativo é carregado. 3 Crie um arquivo de texto updateConfig.xml e adicione o seguinte a ele: <?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://ns.adobe.com/air/framework/update/configuration/1.0"> <url>http://example.com/updates/update.xml</url> <delay>1</delay> </configuration> Edite o elemento URL do arquivo updateConfig.xml para que corresponda à localização eventual do arquivo de descritor de atualização do seu servidor da Web (veja o próximo procedimento). O delay é o número de dias que o aplicativo aguarda entre as verificações de atualizações. 4 Adicione o arquivo updateConfig.xml ao diretório do projeto do seu aplicativo do AIR. 5 Faça com que o objeto updater referencie o arquivo updateConfig.xml e chame o método initialize() do objeto. No ActionScript, use o seguinte código: appUpdater.configurationFile = new File("app:/updateConfig.xml"); appUpdater.initialize(); No JavaScript, use o seguinte código: appUpdater.configurationFile = new air.File("app:/updateConfig.xml"); appUpdater.initialize(); 6 Crie uma segunda versão do aplicativo AIR que tenha uma versão diferente do primeiro aplicativo. (A versão é especificada no arquivo de descritor do aplicativo, no elemento version.) Em seguida, adicione a versão de atualização do aplicativo do AIR ao servidor da Web: 1 Coloque a versão de atualização do arquivo AIR no servidor da Web. 2 Crie um arquivo de texto updateDescriptor.xml e adicione o seguinte conteúdo a ele: <?xml version="1.0" encoding="utf-8"?> <update xmlns="http://ns.adobe.com/air/framework/update/description/1.0"> <version>1.1</version> <url>http://example.com/updates/sample_1.1.air</url> <description>This is the latest version of the Sample application.</description> </update> Edite version, URL e description do arquivo updateDescriptor.xml para que corresponda ao seu arquivo do AIR. 3 Adicione o arquivo updateDescriptor.xml ao mesmo diretório do servidor da Web que contém o arquivo do AIR atualizado. Esse é um exemplo básico, mas fornece a funcionalidade de atualização suficiente para vários aplicativos. O restante deste documento descreve como usar a estrutura de atualização para atender melhor suas necessidades. Para obter outro exemplo de uso da estrutura de atualização, consulte o seguinte aplicativo de amostra no Centro de desenvolvedores do Adobe AIR: Estrutura de atualização em um aplicativo com base no Flash(http://www.adobe.com/go/learn_air_qs_update_framework_flash_en). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 335 Atualização de aplicativos do AIR Definição do arquivo de descritor de atualização a acréscimo do arquivo do AIR ao servidor da Web. Quando você usa a estrutura de atualização do AIR, define informações básicas sobre a atualização disponível em um arquivo de descritor de atualização, armazenado no servidor da Web. O arquivo de descritor de atualização é um arquivo XML simples. A estrutura de atualização incluída no aplicativo verifica esse arquivo para ver se uma nova versão foi carregada. O arquivo de descritor de atualização contém os seguintes dados: • version— A nova versão do aplicativo do air. Deve ser a mesma seqüência de caracteres usada no novo arquivo de descritor do aplicativo air da versão. Se a versão do arquivo de descritor de atualização não corresponder à versão do arquivo do AIR, a estrutura de atualização lançará uma exceção. • url – O local do arquivo do AIR de atualização. Esse arquivo contém a versão de atualização do aplicativo AIR. • description — Detalhes relativos à nova versão. Essas informações podem ser exibidas para o usuário durante o processo de atualização. Os elementos version e url são obrigatórios. O elemento description é opcional. Este é um exemplo de arquivo de descritor de atualização: <?xml version="1.0" encoding="utf-8"?> <update xmlns="http://ns.adobe.com/air/framework/update/description/1.0"> <version>1.1a1</version> <url>http://example.com/updates/sample_1.1a1.air</url> <description>This is the latest version of the Sample application.</description> </update> Se desejar definir a tag description usando vários idiomas, use vários elementos text que definam o atributo lang: <?xml version="1.0" encoding="utf-8"?> <update xmlns="http://ns.adobe.com/air/framework/update/description/1.0"> <version>1.1a1</version> <url>http://example.com/updates/sample_1.1a1.air</url> <description> <text xml:lang="en">English description</text> <text xml:lang="fr">French description</text> <text xml:lang="ro">Romanian description</text> </description> </update> Coloque o arquivo de descritor de atualização no servidor da Web, juntamente com o arquivo de atualização do AIR. O diretório modelo incluído com o descritor de atualização inclui exemplos dos arquivos descritores de atualização. Eles incluem versões com um idioma ou vários idiomas. Instanciação de um objeto atualizador Depois de carregar a estrutura de atualização do AIR em seu código (consulte “Configuração do ambiente de desenvolvimento em Flex” na página 332 e “Inclusão de arquivos de estrutura em um aplicativo do AIR baseado em HTML” na página 333), você deverá instanciar um objeto atualizador, como no exemplo a seguir: var appUpdater:ApplicationUpdater = new ApplicationUpdater(); O código anterior usa a classe ApplicationUpdater (que não fornece interface de usuário). Se você deseja usar a classe ApplicationUpdaterUI (que fornece uma interface de usuário), use o seguinte: var appUpdater:ApplicationUpdaterUI = new ApplicationUpdaterUI(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 336 Atualização de aplicativos do AIR Os exemplos de código restantes neste documento supõem que você tenha instanciado um objeto atualizador appUpdater. Definição das configurações de atualização O ApplicationUpdater e o ApplicationUpdaterUI podem ser configurados por meio de um arquivo de configuração fornecido com o aplicativo ou por meio de ActionScript ou JavaScript no aplicativo. Definição das configurações de atualização em um arquivo de configuração XML O arquivo de configuração de atualização é um arquivo XML. Ele pode conter os seguintes elementos: • updateURL— Uma seqüência de caracteres. Representa a localização do descritor de atualização no servidor remoto. Qualquer localização de URLRequest válida é permitida. Você deve definir a propriedade updateURL pelo arquivo de configuração ou por script (consulte “Definição do arquivo de descritor de atualização a acréscimo do arquivo do AIR ao servidor da Web.” na página 335). Defina essa propriedade antes de usar o atualizador (antes de chamar o método initialize() do objeto atualizador, descrito em “Inicialização da estrutura de atualização” na página 338). • delay— Um número. Representa um intervalo de tempo fornecido em dias (valores como 0,25 são permitidos) para verificação de atualizações. Um valor de 0 (que é o valor padrão) especifica que o atualizador não realiza uma verificação automática periódica. O arquivo de configuração do ApplicationUpdaterUI pode conter o seguinte elemento, além dos elementos updateURL e delay: • defaultUI: Uma lista de elementos dialog. Cada elemento dialog tem um atributo name que corresponde à caixa de diálogo na interface do usuário. Cada elemento dialog tem um atributo visible que define se a caixa de diálogo está visível. O valor padrão é true. Valores possíveis para o atributo name são: • "checkForUpdate" – Corresponde às caixas de diálogo Verificar atualizações, Nenhuma atualização e Erro de atualização. • "downloadUpdate"— Corresponde à caixa de diálogo Fazendo download de atualização. • "downloadProgress"—Corresponde às caixas de diálogo Download em andamento e Erro de download. • "installUpdate"— Corresponde à caixa de diálogo Instalar atualização. • "fileUpdate"— Corresponde às caixas de diálogo Atualização de arquivo, Não atualização de arquivo e Erro de arquivo • "unexpectedError"— Corresponde à caixa de diálogo Erro inesperado Quando definida como false, a caixa de diálogo correspondente não aparece como parte do procedimento de atualização. Este é um exemplo do arquivo de configuração para a estrutura ApplicationUpdater: <?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://ns.adobe.com/air/framework/update/configuration/1.0"> <url>http://example.com/updates/update.xml</url> <delay>1</delay> </configuration> Este é um exemplo do arquivo de configuração para a estrutura ApplicationUpdaterUI, que inclui uma definição para o elemento defaultUI: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 337 Atualização de aplicativos do AIR <?xml version="1.0" encoding="utf-8"?> <configuration xmlns="http://ns.adobe.com/air/framework/update/configuration/1.0"> <url>http://example.com/updates/update.xml</url> <delay>1</delay> <defaultUI> <dialog name="checkForUpdate" visible="false" /> <dialog name="downloadUpdate" visible="false" /> <dialog name="downloadProgress" visible="false" /> </defaultUI> </configuration> Aponte a propriedade configurationFile para o local desse arquivo: como no seguinte • ActionScript: appUpdater.configurationFile = new File("app:/cfg/updateConfig.xml"); • JavaScript: appUpdater.configurationFile = new air.File("app:/cfg/updateConfig.xml"); O diretório modelo da estrutura de atualização inclui um exemplo de arquivo de configuração, o config-template.xml. Definição das configurações de atualização do código ActionScript ou JavaScript Esses parâmetros de configuração também podem ser definidos usando código no aplicativo, como a seguir: appUpdater.updateURL = " http://example.com/updates/update.xml"; appUpdater.delay = 1; As propriedades do objeto atualizador são updateURL e delay. Essas propriedades definem as mesmas configurações dos elementos updateURL e delay no arquivo de configuração: o URL e o arquivo de descritor de atualização e o intervalo de verificação de atualizações. Se você especificar as configurações and de um arquivo de configuração no código, todas as propriedades definidas usando o código terão precedência sobre as configurações correspondentes no arquivo de configuração. Você deve definir a propriedade updateURL por meio do arquivo de configuração ou por meio de script (consulte “Definição do arquivo de descritor de atualização a acréscimo do arquivo do AIR ao servidor da Web.” na página 335) antes de usar o atualizador (antes de chamar o método initialize() do objeto atualizador, descrito em “Inicialização da estrutura de atualização” na página 338). A estrutura ApplicationUpdaterUI define essas propriedades adicionais do objeto atualizador: • isCheckForUpdateVisible – Corresponde às caixas de diálogo Verificar atualizações, Nenhuma atualização e Erro de atualização. • isDownloadUpdateVisible— Corresponde à caixa de diálogo Fazendo download de atualização. • isDownloadProgressVisible —Corresponde às caixas de diálogo Download em andamento e Erro de download. • isInstallUpdateVisible — Corresponde à caixa de diálogo Instalar atualização. • isFileUpdateVisible — Corresponde às caixas de diálogo Atualização de arquivo, Não atualização de arquivo e Erro de arquivo • isUnexpectedErrorVisible — Corresponde à caixa de diálogo Erro inesperado Cada propriedade corresponde a uma ou mais caixa de diálogo da interface de usuário ApplicationUpdaterUI. Cada propriedade é um valor booleano com um valor padrão true. Quando definida como false, a caixa de diálogo correspondente não aparece como parte do procedimento de atualização. Essas propriedades de caixa de diálogo substituem as configurações no arquivo de configuração de atualização. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 338 Atualização de aplicativos do AIR O processo de atualização A estrutura de atualização do AIR completa o processo de atualização nas seguintes etapas: 1 A inicialização do atualizador verifica se foi realizada uma verificação de atualização no intervalo de tempo definido (consulte “Definição das configurações de atualização” na página 336). Se estiver faltando uma verificação de atualização, o processo de atualização continuará. 2 O atualizador baixa e interpreta o arquivo de descritor de atualização. 3 O atualizador baixa o arquivo AIR de atualização. 4 O atualizador instala a versão atualizada do aplicativo. O objeto atualizador despacha eventos na conclusão de cada uma das etapas. Na versão do ApplicationUpdater, você pode cancelar os eventos que indicam a conclusão bem-sucedida de uma etapa no processo. Se você cancelar um desses eventos, a próxima etapa do processo será cancelada. Na versão do ApplicationUpdaterUI, o atualizador apresenta uma caixa de diálogo permitindo que o usuário cancele ou continue para a próxima etapa do processo. Se você cancelar o evento, poderá chamar métodos do objeto atualizador para retomar o processo. Conforme a versão do ApplicationUpdater do atualizador progride pelo processo de atualização, ela registra seu estado atual em uma propriedade currentState. Essa propriedade é definida como uma seqüência de caracteres com os seguintes valores possíveis: • "UNINITIALIZED" — O atualizador não foi inicializado. • "INITIALIZING" — O atualizador está sendo inicializado. • "READY" — O atualizador foi inicializado • "BEFORE_CHECKING" — O atualizador ainda não verificou se existe um arquivo de descritor de atualização. • "CHECKING" — O atualizador está verificando se existe um arquivo de descritor de atualização. • "AVAILABLE" — O arquivo de descritor de atualização está disponível. • "DOWNLOADING" — O atualizador está baixando o arquivo do AIR. • "DOWNLOADED" — O atualizador baixou o arquivo do AIR. • "INSTALLING" — O atualizador está instalando o arquivo do AIR. • "PENDING_INSTALLING" — O atualizador foi inicializado e não há atualizações pendentes. Alguns métodos do objeto atualizador só serão executados se o atualizador estiver em determinado estado. Inicialização da estrutura de atualização Depois de definir as propriedades de configuração (consulte “Exemplo básico: Uso da versão ApplicationUpdaterUI” na página 333), chame o método initialize() para inicializar a atualização: appUpdater.initialize(); Esse método faz o seguinte: • Ele inicializa a estrutura de atualização, instalando de forma silenciosa e síncrona todas as atualizações pendentes. É necessário para chamar esse método durante a inicialização do aplicativo, pois ele pode reiniciar o aplicativo quando chamado. • Ele verifica se existe uma atualização adiada e a instala; • Se houver um erro durante o processo de atualização, ele limpa o arquivo de atualização e as informações de versão da área de armazenamento do aplicativo. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 339 Atualização de aplicativos do AIR • Se o tempo limite tiver expirado, o processo de atualização e iniciado. Caso contrário, ele inicia o timer. Chamar esse método pode resultar no despacho dos seguintes eventos pelo objeto atualizador: • UpdateEvent.INITIALIZED — Despachado quando a inicialização é concluída. • ErrorEvent.ERROR — Despachado quando há um erro na inicialização. No despacho do evento UpdateEvent.INITIALIZED, o processo de atualização é concluído. Quando você chama o método initialize(), o atualizador inicia o processo de atualização e conclui todas as etapas com base na configuração de tempo do timer. No entanto, você também pode iniciar o processo de atualização a qualquer momento chamando o método checkNow() do objeto atualizador: appUpdater.checkNow(); Esse método não faz nada se o processo de atualização já estiver em execução. Caso contrário, ele começa o processo de atualização. O objeto atualizador pode despachar o seguinte evento como resultado de chamar o método checkNow(): • Evento UpdateEvent.CHECK_FOR_UPDATE, antes de ele tentar baixar o arquivo de descritor de atualização. Se você cancelar o evento checkForUpdate, poderá chamar o método checkForUpdate() do objeto atualizador. (Consulte a próxima seção.) Se você não cancelar o evento, o processo de atualização continuará para verificar se há arquivo de descritor de atualização. Gerenciamento do processo de atualização na versão ApplicationUpdaterUI Na versão ApplicationUpdaterUI, o usuário pode cancelar o processo pelos botões Cancelar das caixas de diálogo da interface de usuário. Além disso, você pode cancelar de forma programática o processo de atualização chamando o método cancelUpdate() do objeto ApplicationUpdaterUI. Você pode definir as propriedades do objeto ApplicationUpdaterUI ou definir elementos no arquivo de configuração de atualização para especificar quais confirmações de caixa de diálogo o atualizador exibe. Para obter detalhes, consulte “Definição das configurações de atualização” na página 336. Gerenciamento do processo de atualização na versão ApplicationUpdater Você pode chamar o método preventDefault() dos objetos de evento despachados pelo objeto ApplicationUpdater para cancelar etapas do processo de atualização (consulte “O processo de atualização” na página 338). Cancelar o comportamento padrão fornece ao seu aplicativo uma chance de exibir uma mensagem ao usuário perguntando se ele deseja continuar. As seções a seguir descrevem como continuar o processo de atualização quando uma etapa do processo é cancelada. Download e interpretação do arquivo de descritor de atualização O objeto ApplicationUpdater despacha o evento checkForUpdate antes do processo de atualização ser iniciado, logo antes de o atualizador tentar baixar o arquivo de descritor de atualização. Se você cancelar o comportamento padrão do evento checkForUpdate, o atualizador não baixará o arquivo de descritor de atualização. Você pode chamar o método checkForUpdate() para retomar o processo de atualização: appUpdater.checkForUpdate(); DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 340 Atualização de aplicativos do AIR Chamar o método checkForUpdate() faz com que o atualizador baixe de forma assíncrona e interprete o arquivo de descritor de atualização. Como resultado de chamar o método checkForUpdate(), o objeto atualizador poderá despachar os seguintes eventos: • StatusUpdateEvent.UPDATE_STATUS — O atualizador baixou e interpretou o arquivo de descritor de atualização com êxito. Esse evento tem estas propriedades: • available — Um valor booleano. Defina como true se houver uma versão disponível diferente da versão do aplicativo atual; false, para o contrário (a versão é a mesma). • version — Uma seqüência de caracteres. A versão do arquivo de descritor de aplicativo do arquivo de atualização • details — Uma matriz. Se não houver versões localizadas da descrição, essa matriz retornará uma seqüência de caracteres vazia ("") como primeiro elemento e a descrição como segundo elemento. Se houver várias versões da descrição (no arquivo de descritor de atualização), a matriz conterá várias submatrizes. Cada matriz tem dois elementos: o primeiro é um código de idiomas (como "en") e o segundo é a descrição correspondente (uma seqüência de caracteres) para o idioma. Consulte “Definição do arquivo de descritor de atualização a acréscimo do arquivo do AIR ao servidor da Web.” na página 335. • StatusUpdateErrorEvent.UPDATE_ERROR — Ocorreu e o atualizador não pôde baixar ou interpretar o arquivo de descritor de eventos. Download do arquivo de atualização do AIR O objeto ApplicationUpdater despacha o evento updateStatus depois que o atualizador baixa e interpreta com êxito o arquivo de descritor de atualização. O comportamento padrão é começar a baixar o arquivo de atualização, se ele estiver disponível. Se você cancelar o comportamento padrão, poderá chamar o método downloadUpdate() para retomar o processo de atualização. appUpdater.downloadUpdate(); Chamar esse método faz com que o atualizador baixe de forma assíncrona a versão de atualização do arquivo do AIR. O método downloadUpdate() pode despachar os seguintes eventos: • UpdateEvent.DOWNLOAD_START — Foi estabelecida a conexão com o servidor. Quando você usa a biblioteca ApplicationUpdaterUI, esse evento exibe uma caixa de diálogo com uma barra de progresso para controlar o andamento do download. • ProgressEvent.PROGRESS — Despachado periodicamente conforme o download do arquivo progride. • DownloadErrorEvent.DOWNLOAD_ERROR — Despachado se houver um erro na conexão ou no download do arquivo de atualização. Também é despachado para status de HTTP inválidos (como " 404 - Arquivo não encontrado"). Esse evento tem uma propriedade errorID, um inteiro que define informações de erro adicionais. Uma propriedade subErrorID adicional pode conter mais informações de erro. • UpdateEvent.DOWNLOAD_COMPLETE — O atualizador baixou e interpretou o arquivo de descritor de atualização com êxito. Se você não cancelar esse evento, a versão do ApplicationUpdater continuará a instalar a versão de atualização. Na versão do ApplicationUpdaterUI, o usuário visualiza uma caixa de diálogo que fornece a opção de continuar. Atualização do aplicativo O objeto ApplicationUpdater despacha o evento downloadComplete quando o download do arquivo de atualização é concluído. Se você cancelar o comportamento padrão, poderá chamar o método installUpdate() para retomar o processo de atualização. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 341 Atualização de aplicativos do AIR appUpdater.installUpdate(file); Chamar esse método faz com que o atualizador instale uma versão de atualização do arquivo do AIR. O método inclui um parâmetro, file, que é um objeto File que referencia o arquivo do AIR a ser usado como atualização. O objeto ApplicationUpdater pode despachar e evento beforeInstall como resultado de chamar o método installUpdate(): • UpdateEvent.BEFORE_INSTALL — Despachado antes de instalar a atualização. Às vezes, é útil impedir a instalação da atualização nesse momento, para que o usuário possa concluir o trabalho atual antes de a atualização continuar. Chamar o método preventDefault() do objeto Event adia a instalação até o próximo reinício, e nenhum processo de atualização adicional pode ser iniciado. (Isso inclui atualizações que resultariam de chamar o método checkNow() ou de verificações periódicas.) Instalação de um arquivo do AIR arbitrário Você pode chamar o método installFromAIRFile() para instalar a versão de atualização para instalar de um arquivo do AIR no computador do usuário. appUpdater.installFromAIRFile(); Esse método faz com que o atualizador instale uma versão de atualização do aplicativo a partir do arquivo do AIR. O método installFromAIRFile() pode despachar os seguintes eventos: • StatusFileUpdateEvent.FILE_UPDATE_STATUS — Despachado depois que ApplicationUpdater valida com êxito o arquivo envaido usando o método installFromAIRFile(). Esse evento tem as seguintes propriedades: • available — Definida como true se houver uma versão diferente da versão do aplicativo atual; false caso contrário (as versões são as mesmas). • version — A string que representa a nova versão disponível. • path — Representa o caminho nativo do arquivo de atualização. Você pode cancelar esse evento se a propriedade disponível do objeto StatusFileUpdateEvent estiver definida como true. O cancelamento do evento impede a continuidade da atualização. Chame o método installUpdate() para continuar a atualização cancelada. • StatusFileUpdateErrorEvent.FILE_UPDATE_ERROR — Ocorreu um erro e o atualizador não pôde instalar o aplicativo AIR. Cancelamento do processo de atualização Você pode chamar o método cancelUpdate() para cancelar o processo de atualização: appUpdater.cancelUpdate(); Esse método cancela os downloads pendentes, excluindo arquivos baixados incompletos, e reinicia o timer de verificação periódica. O método não faz nada se o objeto atualizador estiver sendo inicializado. Localização da interface ApplicationUpdaterUI A classe ApplicationUpdaterUI fornece uma interface de usuário padrão para o processo de atualização. Isso inclui caixas de diálogo que permitem que o usuário inicie o processo, cancele o processo e realize outras ações relacionadas. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 342 Atualização de aplicativos do AIR O elemento description do arquivo de descritor de atualização permite definir a descrição do aplicativo em vários idiomas. Use vários elementos text que definem atributos lang, como a seguir: <?xml version="1.0" encoding="utf-8"?> <update xmlns="http://ns.adobe.com/air/framework/update/description/1.0"> <version>1.1a1</version> <url>http://example.com/updates/sample_1.1a1.air</url> <description> <text xml:lang="en">English description</text> <text xml:lang="fr">French description</text> <text xml:lang="ro">Romanian description</text> </description> </update> A estrutura de atualização usa a descrição mais adequada para a cadeia de localização do usuário. Para obter mais informações, consulte Definição do arquivo de descritor de atualização a acréscimo do arquivo do AIR ao servidor da Web. Desenvolvedores de Flex podem adicionar diretamente um novo idioma ao grupo "ApplicationUpdaterDialogs". Desenvolvedores de JavaScript podem chamar o método addResources() do objeto atualizador. Esse método adiciona dinamicamente um novo conjunto de recursos para um idioma. O conjunto de recursos define seqüências de caracteres localizadas para um idioma. Essas seqüências de caracteres são usadas em vários campos de texto de caixa de diálogo. Desenvolvedores de JavaScript podem usar a propriedade localeChain da classe ApplicationUpdaterUI para definir a cadeia de localização usada pela interface do usuário. Geralmente, somente desenvolvedores de JavaScript (HTML) usam essa propriedade. Desenvolvedores de Flex usam o ResourceManager para gerenciar a cadeia de localização. Por exemplo, o código de JavaScript a seguir define grupos de recursos para romano e húngaro. appUpdater.addResources("ro_RO", {titleCheck: "Titlu", msgCheck: "Mesaj", btnCheck: "Buton"}); appUpdater.addResources("hu", {titleCheck: "Cím", msgCheck: "Üzenet"}); var languages = ["ro", "hu"]; languages = languages.concat(air.Capabilities.languages); var sortedLanguages = air.Localizer.sortLanguagesByPreference(languages, air.Capabilities.language, "en-US"); sortedLanguages.push("en-US"); appUpdater.localeChain = sortedLanguages; Para obter detalhes, consulte a descrição do método addResources() da classe ApplicationUpdaterUI na referência de idiomas. 343 Capítulo 34: Localização de aplicativos AIR O Adobe® AIR™ 1.1 inclui suporte para vários idiomas. Introdução à localização Localização é o processo de inclusão de recursos para oferecer suporte a vários códigos de idiomas. Código de idiomas é a combinação de um idioma e um código de um país. Por exemplo, en_US se refere ao idioma inglês falado nos Estados Unidos e fr_FR se refere ao idioma francês falado na França. Para localizar um aplicativo para esses códigos de idiomas, você fornece dois conjuntos de recursos: um para o código de idioma en_US e um para o código de idiomas fr_FR. Os códigos de idiomas podem compartilhar idiomas. Por exemplo, en_US e en_GB (Grã-Bretanha) são códigos de idiomas diferentes. Nesse caso, os dois códigos de idiomas usam o idioma inglês, mas o código do país indica que são códigos de idiomas diferentes e podem, portanto, usar recursos diferentes. Por exemplo, um aplicativo no código de idioma sen_US pode escrever a palavra "color", ao passo que ela seria "colour" no código de idiomas en_GB. Além disso, unidades monetárias seriam representadas em dólares ou em libras, dependendo do código de idiomas, e o formato de data e hora também pode ser diferente. Você também podem fornecer um conjunto de recursos para um idioma sem especificar o código do país. Por exemplo, você pode fornecer recursos en para o idioma Inglês e fornecer recursos adicionais do código de idiomas en_US, específicos para inglês dos EUA. O AIR SDK oferece uma estrutura de localização HTML (contida no arquivo AIRLocalizer.js). Essa estrutura inclui APIs que auxiliam no trabalho com vários códigos de idiomas. Para obter detalhes, consulte “Localização de conteúdo HTML” na página 344. A localização vai além de só traduzir as seqüências usadas no aplicativo. Ela também pode incluir qualquer tipo de recurso, como arquivos de áudio, imagens e vídeos. Localização do nome e da descrição do aplicativo no instalador do aplicativo Você pode especificar vários idiomas para os elementos name e description no arquivo do descritor do aplicativo. Por exemplo, o seguinte especifica o nome do aplicativo em três idiomas (inglês, francês e alemão): <name> <text xml:lang="en">Sample 1.0</text> <text xml:lang="fr">Échantillon 1.0</text> <text xml:lang="de">Stichprobe 1.0</text> </name> O atributo xml:lang de cada elemento de texto especifica um código de idioma, como definido por RFC4646 (http://www.ietf.org/rfc/rfc4646.txt). DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 344 Localização de aplicativos AIR O elemento name define o nome do aplicativo que o instalador de aplicativo do AIR exibe. O instalador de aplicativo do AIR usa o valor localizado que melhor corresponda aos idiomas da interface do usuário definidos pelas configurações do sistema operacional. De modo semelhante, você pode especificar várias versões de idioma do elemento description no arquivo do descritor do aplicativo. Esse elemento define o texto de descrição que instalador de aplicativo do AIR exibe. Essas configurações só se aplicam aos idiomas disponíveis no instalador de aplicativo do AIR. Elas não definem os códigos de idiomas disponíveis para a execução do aplicativo instalado. Os aplicativo do AIR pode oferecer interfaces do usuário que oferecem suporte a vários idiomas, incluindo e além daquelas disponíveis no instalador de aplicativo do AIR. Para obter mais informações, consulte “Definição de propriedades no arquivo do descritor do aplicativo” na página 45. Seleção de código de idiomas Para determinar que código de idiomas o aplicativo usa, você pode usar um dos seguintes métodos: • Prompt de usuário: você pode iniciar o aplicativo em algum código de idiomas padrão e, então, solicitar ao usuário que selecione o código de idiomas preferido. • Capabilities.languages: a propriedade Capabilities.languages lista uma matriz de idiomas disponíveis nos idiomas de preferência do usuário, conforme definido pelo sistema operacional. As seqüências contêm tags de idioma (e informações de script e região, quando aplicável) definidas por RFC4646 (http://www.ietf.org/rfc/rfc4646.txt). As seqüências usam hífens como delimitadores (por exemplo, "en-US" ou "ja-JP"). A primeira entrada na matriz retornada tem a mesma ID de idioma principal da propriedade language. Por exemplo, se languages[0] for definido como "en-US", a propriedade language será definida como "en". Entretanto, se a propriedade language for definida como "xu" (especificando um idioma desconhecido), o primeiro elemento na matriz languages será diferente. • Capabilities.language: a propriedade Capabilities.language oferece o código de idioma da interface do usuário do sistema operacional. No entanto, essa propriedade está limitada a 20 idiomas conhecidos. E, nos sistemas em inglês, essa propriedade retorna somente o código do idioma, não o código do país. Por esses motivos, é melhor usar o primeiro elemento na matriz Capabilities.languages. Localização de conteúdo Flash O Flash CS3 e Flash CS4 incluem a classe Locale nos componentes do ActionScript 3.0. A classe Locale permite controlar como o arquivo SWF exibe o texto multilíngüe. O painel Strings do Flash permite usar IDs de string em vez de literais de string nos campos de texto dinâmicos. Isso permite criar um arquivo SWF que exibe o texto carregado de um arquivo XML específico do idioma. Para obter informações sobre o uso da classe Locale, consulte a Referência dos componentes e da linguagem do ActionScript 3.0 do Flash. Localização de conteúdo HTML O AIR 1.1 SDK inclui uma estrutura de localização HTML. O arquivo de JavaScript AIRLocalizer.js define a estrutura. O diretório de estruturas do AIR SDK contém o arquivo AIRLocalizer.js. Esse arquivo inclui a classe Localizer, que oferece funcionalidade para auxiliar na criação de aplicativos que ofereçam suporte a várias versões localizadas. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 345 Localização de aplicativos AIR Carregamento do código de estrutura de localização HTML do AIR. Para usar a estrutura de localização, copie o arquivo AIRLocalizer.js em seu projeto. Em seguida, inclua-a no arquivo HTML principal do aplicativo, usando uma tag de script: <script src="AIRLocalizer.js" type="text/javascript" charset="utf-8"></script> Em seguida, o JavaScript pode chamar o objeto air.Localizer.localizer: <script> var localizer = air.Localizer.localizer; </script> O objeto air.Localizer.localizer é um objeto singleton que define métodos e propriedades para usar e gerenciar recursos de localização. A classe Localizer inclui os seguintes métodos: Método Descrição getFile() Obtém o texto de um grupo de recursos especificados para um código de idiomas especificado. Consulte “Obtenção de recursos para um código de idiomas específico.” na página 351. getLocaleChain() Retorna os idiomas na cadeia de código de idiomas. Consulte “Definição da cadeia de código de idiomas” na página 350. getResourceBundle() Retorna as chaves do grupo e os valores correspondentes como um objeto. Consulte “Obtenção de recursos para um código de idiomas específico.” na página 351. getString() Obtém a seqüência definida para um recurso. Consulte “Obtenção de recursos para um código de idiomas específico.” na página 351. setBundlesDirectory( ) Define o local do diretório de compactados. Consulte “Personalização de configurações HTML Localizer do AIR” na página 349. setLocalAttributePre fix() Define o prefixo usado pelos atributos do localizer usados nos elementos HTML DOM. Consulte “Personalização de configurações HTML Localizer do AIR” na página 349 setLocaleChain() Define a ordem de idiomas na cadeia de código de idiomas. Consulte “Definição da cadeia de código de idiomas” na página 350. sortLanguagesByPrefe rence() Classifica os códigos de idiomas na cadeia de código de idiomas com base na ordem de códigos de idiomas nas configurações do sistema operacional. Consulte “Definição da cadeia de código de idiomas” na página 350. update() Atualiza o HTML DOM (ou um elemento DOM) com seqüências localizadas da cadeia de código de idiomas atual. Para obter uma discussão sobre cadeias de códigos de idiomas, consulte “Gerenciamento de cadeias de códigos de idiomas” na página 347. Para obter mais informações sobre o método update(), consulte “Atualização de elementos DOM para uso de código de idiomas atual” na página 348. A classe Localizer inclui as seguintes propriedades estáticas: Propriedade Descrição localizer Retorna uma referência para o objeto singleton Localizer do aplicativo. ultimateFallbackLocale Código de idiomas usado quando o aplicativo não oferece suporte a nenhuma preferência de usuário. Consulte “Definição da cadeia de código de idiomas” na página 350. Definição de grupos de recursos A estrutura de localização HTML faz a leitura de versões localizadas de seqüências de arquivos de localização. O arquivo de localização é um conjunto de valores baseados em chaves, serializados em um arquivo de texto. O arquivo de localização é algumas vezes tratado como um compactado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 346 Localização de aplicativos AIR Crie um subdiretório do diretório de projeto do aplicativo, chamado código de idiomas. (Você também pode usar um nome diferente; consulte “Personalização de configurações HTML Localizer do AIR” na página 349.) Esse diretório incluirá os arquivos de localização. Esse diretório é conhecido como o diretório de compactações. Para cada código de idiomas a que seu aplicativo oferece suporte, crie um subdiretório do diretório de compactações. Nomeie cada subdiretório para corresponder ao código de idiomas. Por exemplo, nomeie o diretório French como "fr" e o diretório English como "en". Você pode usar o caractere sublinhado (_) para definir o código de idiomas que tenha um código de país e idioma. Por exemplo, nomeie o diretório U.S. English como “en_us”. (Como alternativa, você pode usar um hífen, em vez de um sublinhado, como em “en-us.” A estrutura de localização HTML oferece suporte às duas opções). Você pode adicionar qualquer número de arquivos de recursos a um subdiretório código de idiomas. Normalmente, você cria um arquivo de localização para cada idioma (e coloca o arquivo no diretório desse idioma). A estrutura de localização HTML inclui o método getFile() que permite ler o conteúdo de um arquivo (consulte “Obtenção de recursos para um código de idiomas específico.” na página 351. Arquivos com a extensão de arquivo .properties são conhecidos como arquivos de propriedades de localização. Você pode usá-los para definir pares de valores chave para um código de idiomas. O arquivo de propriedade define um valor de seqüência em cada linha. Por exemplo, o seguinte define o valor de seqüência "Oi em inglês". para uma chave de nome greeting: greeting=Hello in English. O arquivo de propriedades contendo o texto a seguir define seis pares de valores chave: title=Sample Application greeting=Hello in English. exitMessage=Thank you for using the application. color1=Red color2=Green color3=Blue Este exemplo mostra uma versão em inglês do arquivo de propriedades que deve ser armazenado no diretório en. A versão francesa desse arquivo de propriedades é colocada no diretório fr: title=Application Example greeting=Bonjour en français. exitMessage=Merci d'avoir utilisé cette application. color1=Rouge color2=Vert color3=Bleu Você pode definir vários arquivos de recursos para tipos diferentes de informações. Por exemplo, o arquivo legal.properties pode conter texto de padrão legal (como informações de direitos autorais). Talvez você deseje reutilizar esse recurso em vários aplicativos. De modo semelhante, você pode definir arquivos distintos que definem conteúdo localizado de diferentes partes da interface do usuário. Use a codificação UTF-8 para esses arquivos, para oferecer suporte a vários idiomas. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 347 Localização de aplicativos AIR Gerenciamento de cadeias de códigos de idiomas Quando o aplicativo carrega o arquivo AIRLocalizer.js, ele examina os códigos de idiomas definidos no aplicativo. Esses códigos de idiomas correspondem aos subdiretórios do diretório de compactações (consulte “Definição de grupos de recursos” na página 345). Essa lista de códigos de idiomas disponíveis é conhecida como a cadeia de código de idiomas. O arquivo AIRLocalizer.js classifica automaticamente a cadeia de código de idiomas com base na ordem de preferência definida pelas configurações do sistema operacional. (A propriedade Capabilities.languages lista os idiomas da interface do usuário do sistema operacional, por ordem de preferência). Portanto, se um aplicativo define recursos para os códigos de idiomas "en", "en_US" e "en_UK", a estrutura HTML Localizer do AIR classifica a cadeia de código de idiomas de maneira apropriada. Quando o aplicativo é iniciado em um sistema que informa "en" como código de idiomas principal, a cadeia de código de idiomas é classificada como ["en", "en_US", "en_UK"]. Nesse caso o aplicativo procura primeiramente por recursos no grupo "en" e, em seguida, no grupo "en_US". No entanto, se o sistema informar "en-US" como código de idiomas principal, a classificação usará ["en_US", "en", en_UK"]. Nesse caso, o aplicativo procura primeiramente recursos no grupo "en_US" e, em seguida, no grupo "en". Por padrão, o aplicativo define o primeiro código de idiomas na cadeia de código de idiomas como o código de idiomas padrão para usar. Você pode solicitar que o usuário selecione um código de idiomas na primeira execução do aplicativo. Em seguida, você pode optar por armazenar a seleção em um arquivo de preferências e usar esse código de idiomas na inicialização subseqüente do aplicativo. O aplicativo pode usar as seqüências de recursos em qualquer código de idiomas da cadeia de código de idiomas. Se um código de idiomas específico não definir uma seqüência de recursos, o aplicativo usará a próxima seqüência de recursos correspondente em outros códigos de idiomas definidos na cadeia de código de idiomas. Você pode personalizar a cadeia de código de idiomas chamando o método setLocaleChain() do objeto Localizer. Consulte “Definição da cadeia de código de idiomas” na página 350. Atualização de elementos DOM com conteúdo localizado O elemento no aplicativo pode fazer referência a um valor chave em um arquivo de propriedades de localização. Por exemplo, o elemento title no exemplo a seguir especifica um atributo local_innerHTML. A estrutura de localização usa esse atributo para pesquisar um valor localizado. Por padrão, a estrutura pesquisa nomes de atributos que iniciam com "local_". A estrutura atualiza os atributos com nomes que correspondem ao texto em seguida a "local_". Nesse caso, a estrutura define o atributo innerHTML do elemento title. O atributo innerHTML usa o valor definido para a chave mainWindowTitle no arquivo de propriedades padrão (default.properties): <title local_innerHTML="default.mainWindowTitle"/> Se o código de idiomas atual não definir nenhum valor correspondente, a estrutura do localizador procura o restante da cadeia de códigos de idiomas. Ele usa o próximo código de idiomas na cadeia de código de idiomas para o qual um valor está definido. No exemplo a seguir, o texto (atributo innerHTML) do elemento p usa o valor da chave greeting definido no arquivo de propriedades padrão: <p local_innerHTML="default.greeting" /> No exemplo a seguir, o atributo de valor (e texto exibido) do elemento input usa o valor da chave btnBlue definido no arquivo de propriedades padrão: <input type="button" local_value="default.btnBlue" /> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 348 Localização de aplicativos AIR Para atualizar o HTML DOM para usar as seqüências definidas na cadeia de código de idiomas atual, chame o método update() do objeto Localizer. Chamar o método update() faz com que o objeto Localizer analise o DOM e aplique manipulações onde encontrar atributos de localização "local_..."): air.Localizer.localizer.update(); Você pode definir valores tanto para um atributo (como "innerHTML") quanto para o respectivo atributo de localização correspondente (como "local_innerHTML"). Nesse caso, a estrutura de localização só sobrescreve o valor de atributo se ela encontrar um valor correspondente na cadeia de localização. Por exemplo, o elemento a seguir define os atributos value e local_value: <input type="text" value="Blue" local_value="default.btnBlue"/> Você também pode atualizar apenas um elemento DOM específico Consulte a próxima seção, “Atualização de elementos DOM para uso de código de idiomas atual” na página 348. Por padrão, o HTML Localizer do AIR usa "local_" como o prefixo de atributos que definem as configurações de localização do elemento. Por exemplo, por padrão, o atributo local_innerHTML define o nome do grupo e recurso usados no valor innerHTML do elemento. Além disso, por padrão, o atributo local_value define o nome do grupo e recurso usados no atributo value do elemento. Você pode configurar o Localizer para usar um prefixo de atributo além de "local_". Consulte “Personalização de configurações HTML Localizer do AIR” na página 349. Atualização de elementos DOM para uso de código de idiomas atual Quando o objeto Localizer atualiza o HTML DOM, isso faz com que elementos marcados usem valores de atributos com base nas seqüências definidas na cadeia de código de idiomas atual. Para fazer com que o localizador HTML atualize o HTML DOM, chame o método update() do objeto Localizer: air.Localizer.localizer.update(); Para atualizar apenas um elemento DOM especificado, passe-o como parâmetro para o método update(). O método update() só tem um parâmetro, parentNode, que é opcional. Quando especificado, o parâmetro parentNode define o elemento DOM para ser localizado. Chamar o método update() e especificar o parâmetro parentNode define os valores localizados de todos os elementos filhos que especificam atributos de localização. Por exemplo, considere o seguinte elemento div: <div id="colorsDiv"> <h1 local_innerHTML="default.lblColors" ></h1> <p><input type="button" local_value="default.btnBlue" /></p> <p><input type="button" local_value="default.btnRed" /></p> <p><input type="button" local_value="default.btnGreen" /></p> </div> Para atualizar esse elemento para usar as seqüências localizadas definidas na cadeia de código de idiomas atual, use o seguinte código JavaScript: var divElement = window.document.getElementById("colorsDiv"); air.Localizer.localizer.update(divElement); Se o valor chave não for encontrado na cadeia de código de idiomas, a estrutura de localização definirá o valor de atributo como o valor do atributo "local_". Por exemplo, no exemplo anterior, suponhamos que a estrutura de localização não possa encontrar o valor da chave lblColors (em qualquer um dos arquivos default.properties na cadeia de código de idiomas). Nesse caso, ela usará "default.lblColors" como valor innerHTML. Usar esse valor indica (para o desenvolvedor) ausência de recursos. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 349 Localização de aplicativos AIR O método update() despacha o evento resourceNotFound quando não consegue encontrar um recurso na cadeia de código de idiomas. A constante air.Localizer.RESOURCE_NOT_FOUND define a seqüência "resourceNotFound". O evento tem três propriedades: bundleName, resourceName e locale. A propriedade bundleName é o nome do grupo em que o recurso não foi encontrado. A propriedade resourceName é o nome do grupo em que o recurso não foi encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. O método update() despacha o evento bundleNotFound quando não consegue encontrar o grupo especificado. A constante air.Localizer.BUNDLE_NOT_FOUND define a seqüência "bundleNotFound". O evento tem duas propriedades: bundleName e locale. A propriedade bundleName é o nome do grupo em que o recurso não foi encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. O método update() funciona de forma assíncrona (e despacha os eventos resourceNotFound e bundleNotFound de forma assíncrona). O código a seguir define ouvintes de evento dos eventos resourceNotFound e bundleNotFound: air.Localizer.localizer.addEventListener(air.Localizer.RESOURCE_NOT_FOUND, rnfHandler); air.Localizer.localizer.addEventListener(air.Localizer.BUNDLE_NOT_FOUND, rnfHandler); air.Localizer.localizer.update(); function rnfHandler(event) { alert(event.bundleName + ": " + event.resourceName + ":." + event.locale); } function bnfHandler(event) { alert(event.bundleName + ":." + event.locale); } Personalização de configurações HTML Localizer do AIR O método setBundlesDirectory() do objeto Localizer permite personalizar o caminho do diretório de compactações. O método setLocalAttributePrefix() do objeto Localizer permite personalizar o caminho do diretório de compactações e personalizar o valor de atributo usado pelo Localizer. O diretório de compactações padrão é definido como o subdiretório código de idiomas do diretório do aplicativo. Você pode especificar outro diretório chamando o método setBundlesDirectory() do objeto Localizer. Esse método usa o parâmetro path, que é o caminho para o diretório de compactações desejado, como uma seqüência. O valor do parâmetro path pode ser algum dos seguintes: • Uma seqüência que define o caminho relativo para o diretório do aplicativo, como "locales" • Uma seqüência que define a URL válida que usa os esquemas de URL app, app-storage ou file, como "app://languages" (não usa o esquema de URL http) • O objeto File Para obter informações sobre caminhos de diretórios e URLs, consulte “Caminhos de objetos File” na página 107. Por exemplo, o código a seguir define o diretório de compactações como subdiretório de idiomas do diretório de armazenamento do aplicativo (não o diretório de aplicativo): air.Localizer.localizer.setBundlesDirectory("languages"); Passe um caminho válido como o parâmetro path. Do contrário, o método emitirá uma exceção BundlePathNotFoundError. Esse erro tem "BundlePathNotFoundError" como sua propriedade name e a respectiva propriedade message especifica o caminho inválido. Por padrão, o HTML Localizer do AIR usa "local_" como o prefixo de atributos que definem as configurações de localização do elemento. Por exemplo, o atributo local_innerHTML define o nome do grupo e recurso usado no valor innerHTML do seguinte elemento input: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 350 Localização de aplicativos AIR <p local_innerHTML="default.greeting" /> O método setLocalAttributePrefix() do objeto Localizer permite usar outro prefixo de atributo que não seja "local_". Esse método estático usa um parâmetro, que é a seqüência que você deseja usar como prefixo de atributo. Por exemplo, o código a seguir define que a estrutura de localização use "loc_" como o prefixo de atributo: air.Localizer.localizer.setLocalAttributePrefix("loc_"); Você pode personalizar o prefixo de atributo que a estrutura de localização utiliza. Talvez você deseje personalizar o prefixo, caso o valor padrão ("local_") entre em conflito com o nome de outro atributo usado por seu código. Certifique-se de usar caracteres válidos em atributos HTML quando chamar esse método. (Por exemplo, o valor não pode conter um caractere de espaço em branco). Para obter mais informações sobre como usar os atributos de localização em elementos HTML, consulte “Atualização de elementos DOM com conteúdo localizado” na página 347. As configurações do diretório de compactações e prefixo de atributo não persistem entre sessões de aplicativos diferentes. Se você usar uma configuração personalizada de diretório de compactações ou de prefixo de atributo, certifique-se de defini-las sempre que iniciar o aplicativo. Definição da cadeia de código de idiomas Por padrão, quando você carrega o código AIRLocalizer.js, ele define a cadeia de código de idiomas padrão. Os códigos de idiomas disponíveis nas configurações de diretório de compactações e de idioma do sistema operacional definem essa cadeia de código de idiomas. (Para obter detalhes, consulte “Gerenciamento de cadeias de códigos de idiomas” na página 347). Você pode modificar a cadeia de código de idiomas chamando o método estático setLocaleChain() do objeto Localizer. Por exemplo, talvez você deseje chamar esse método se o usuário indicar a preferência por um idioma específico. O método setLocaleChain() usa um parâmetro, chain, que é uma matriz de códigos de idiomas, como ["fr_FR","fr","fr_CA"]. A ordem dos códigos de idiomas na matriz define a ordem em que a estrutura pesquisa recursos (em operações subseqüentes). Se o recurso não for encontrado para o primeiro código de idiomas na cadeia, ele continua pesquisando em outros recursos de códigos de idiomas. Se o argumento chain estiver ausente, se não for uma matriz ou for uma matriz vazia, a função falhará e emitirá uma exceção IllegalArgumentsError. O método estático getLocaleChain() do objeto Localizer retorna uma matriz que lista os códigos de idiomas na cadeia de código de idiomas atual. O código a seguir faz a leitura da cadeia de código de idiomas atual e adiciona dois códigos de idiomas franceses ao cabeçalho da cadeia: var currentChain = air.Localizer.localizer.getLocaleChain(); newLocales = ["fr_FR", "fr"]; air.Localizer.localizer.setLocaleChain(newLocales.concat(currentChain)); O método setLocaleChain() despacha o evento "change" quando atualiza a cadeia de código de idiomas. A constante air.Localizer.LOCALE_CHANGE define a seqüência "change". O evento tem uma propriedade, localeChain, uma matriz de códigos de idiomas na nova cadeia de código de idiomas. O código a seguir define um ouvinte de evento para esse evento: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 351 Localização de aplicativos AIR var currentChain = air.Localizer.localizer.getLocaleChain(); newLocales = ["fr_FR", "fr"]; localizer.addEventListener(air.Localizer.LOCALE_CHANGE, changeHandler); air.Localizer.localizer.setLocaleChain(newLocales.concat(currentChain)); function changeHandler(event) { alert(event.localeChain); } A propriedade estática air.Localizer.ultimateFallbackLocale representa o código de idiomas usado quando o aplicativo não oferece suporte a nenhuma preferência do usuário. O valor padrão é "en". Você pode defini-lo como outro código de idiomas, como mostrado no código a seguir: air.Localizer.ultimateFallbackLocale = "fr"; Obtenção de recursos para um código de idiomas específico. O método getString() do objeto Localizer retorna a seqüência definida para um recurso em um código de idiomas específico. Não é necessário especificar o valor locale ao chamar o método. Nesse caso, o método procura em toda a cadeia de código de idiomas e retorna a seqüência no primeiro código de idiomas que fornece o nome de recurso determinado. O método tem os seguintes parâmetros: Parâmetro Descrição bundleName O grupo que contém o recurso. Esse é o nome de arquivo do arquivo de propriedades sem a extensão .properties. (Por exemplo, se esse parâmetro for definido como "alerts", o código Localizer pesquisará nos arquivos de localização chamados alerts.properties. resourceName O nome do recurso. templateArgs Opcional. A matriz de seqüência para substituir as tags numeradas na seqüência de substituição. Por exemplo, considere uma chamada para a função em que o parâmetro templateArgs seja ["Raúl", "4"] e a seqüência de recursos correspondente seja "Hello, {0}. Você tem {1} mensagens novas.". Nesse caso, a função retorna "Hello, Raúl. Você tem 4 mensagens novas".. Para ignorar essa configuração, passe o valor null. locale Opcional. O código de idiomas (como "en", "en_us" ou "fr") que deve ser usado. Se o código de idiomas for fornecido e nenhum valor correspondente for encontrado, o método não continuará a busca por valores em outros códigos de idiomas na cadeia de código de idiomas. Se nenhum código de idiomas for especificado, a função retornará a seqüência no primeiro código de idiomas na cadeia de código de idiomas que ofereça o valor para o nome de recurso determinado. A estrutura de localização pode atualizar atributos HTML DOM marcados. No entanto, você pode usar seqüências localizadas de outras maneiras. Por exemplo, você pode usar uma seqüência em HTMLs gerados dinamicamente ou como valor de parâmetro em uma chamada de função. Por exemplo, o código a seguir chama a função alert() com a seqüência definida no recurso error114 no arquivo de propriedades padrão do código de idiomas fr_FR: alert(air.Localizer.localizer.getString("default", "error114", null, "fr_FR")); O método getString() despacha o evento resourceNotFound quando não consegue encontrar o recurso no grupo especificado. A constante air.Localizer.RESOURCE_NOT_FOUND define a seqüência "resourceNotFound". O evento tem três propriedades: bundleName, resourceName e locale. A propriedade bundleName é o nome do grupo em que o recurso não foi encontrado. A propriedade resourceName é o nome do grupo em que o recurso não foi encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 352 Localização de aplicativos AIR O método getString() despacha o evento bundleNotFound quando não consegue encontrar o grupo especificado. A constante air.Localizer.BUNDLE_NOT_FOUND define a seqüência "bundleNotFound". O evento tem duas propriedades: bundleName e locale. A propriedade bundleName é o nome do grupo em que o recurso não foi encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. O método getString() opera de forma assíncrona (e despacha os eventos resourceNotFound e resourceNotFound de forma assíncrona). O código a seguir define ouvintes de evento dos eventos resourceNotFound e bundleNotFound: air.Localizerlocalizer.addEventListener(air.Localizer.RESOURCE_NOT_FOUND, rnfHandler); air.Localizerlocalizer.addEventListener(air.Localizer.BUNDLE_NOT_FOUND, bnfHandler); var str = air.Localizer.localizer.getString("default", "error114", null, "fr_FR"); function rnfHandler(event) { alert(event.bundleName + ": " + event.resourceName + ":." + event.locale); } function bnfHandler(event) { alert(event.bundleName + ":." + event.locale); } O método getResourceBundle() do objeto Localizador retorna um grupo especificado para um determinado local. O valor de retorno do método é um objeto com propriedades correspondentes às chaves do grupo. (Se o aplicativo não puder localizar o grupo especificado, o método retornará null.) O método assume dois parâmetros - locale e bundleName. Parâmetro Descrição locale O local (como "fr"). bundleName O nome do grupo. Por exemplo, o código a seguir chama o método document.write() para carregar o grupo padrão para o local fr. Em seguida, ele chama o método document.write() com valores das chaves str1 e str2 do grupo: var aboutWin = window.open(); var bundle = localizer.getResourceBundle("fr", "default"); aboutWin.document.write(bundle.str1); aboutWin.document.write("<br/>"); aboutWin.document.write(bundle.str2); aboutWin.document.write("<br/>"); O método getResourceBundle() despacha o evento bundleNotFound quando não consegue encontrar o grupo especificado. A constante air.Localizer.BUNDLE_NOT_FOUND define a seqüência "bundleNotFound". O evento tem duas propriedades: bundleName e locale. A propriedade bundleName é o nome do grupo em que o recurso não foi encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. O método getFile() do objeto Localizer retorna o conteúdo de um grupo, como uma seqüência, para um código de idiomas determinado. O arquivo de compactação é interpretado como arquivo UTF-8. O método inclui os seguintes parâmetros: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 353 Localização de aplicativos AIR Parâmetro Descrição resourceFileName Nome de arquivo do arquivo de recurso (como "about.html"). templateArgs Opcional. A matriz de seqüência para substituir as tags numeradas na seqüência de substituição. Por exemplo, considere uma chamada para a função em que o parâmetro templateArgs seja ["Raúl", "4"] e o arquivo de recursos correspondente contenha duas linhas: <html> <body>Hello, {0}. You have {1} new messages.</body> </html> Nesse caso, a função retorna uma seqüência com duas linhas: <html> <body>Hello, Raúl. You have 4 new messages. </body> </html> locale O código de idiomas, como "en_GB", que deve ser usado. Se o código de idiomas for fornecido e nenhum arquivo correspondente for encontrado, o método não continuará a busca em outros códigos de idiomas na cadeia de código de idiomas. Se o código de idiomas no for especificado, a função retornará o texto no primeiro código de idiomas na cadeia de código de idiomas com um arquivo que corresponda a resourceFileName. Por exemplo, o código a seguir chama o método document.write() usando o conteúdo do arquivo about.html do código de idiomas fr: var aboutWin = window.open(); var aboutHtml = localizer.getFile("about.html", null, "fr"); aboutWin.document.close(); aboutWin.document.write(aboutHtml); O método getFile() despacha o evento fileNotFound quando não consegue encontrar um recurso na cadeia de código de idiomas. A constante air.Localizer.FILE_NOT_FOUND define a seqüência "resourceNotFound". O método getFile() funciona de forma assíncrona (e despacha o evento fileNotFound de forma assíncrona). O evento tem duas propriedades: fileName e locale. A propriedade fileName é o nome do arquivo não encontrado. A propriedade locale é o nome do código de idiomas em que o recurso não foi encontrado. O código a seguir define um ouvinte de evento para esse evento: air.Localizer.localizer.addEventListener(air.Localizer.FILE_NOT_FOUND, fnfHandler); air.Localizer.localizer.getFile("missing.html", null, "fr"); function fnfHandler(event) { alert(event.fileName + ": " + event.locale); } Localização de datas, horas e moedas A maneira como os aplicativos apresentam dados, horas e moedas varia consideravelmente em cada código de idiomas. Por exemplo, o padrão dos EUA para representação de datas é mês/dia/ano, enquanto o padrão europeu para representação de datas é dia/mês/ano. Você pode gravar um código para formatar datas, horas e moedas. Por exemplo, o código a seguir converte o objeto Date no formato mês/dia/ano ou no formato dia/mês/ano. Se a variável locale (representando o código de idiomas) for definida como "en_US", a função retornará o formato mês/dia/ano. O exemplo converte o objeto Date no formato dia/mês/ano de todos os outros códigos de idiomas: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 354 Localização de aplicativos AIR function convertDate(date) { if (locale == "en_US") { return (date.getMonth() + 1) + "/" + date.getDate() + "/" + date.getFullYear(); } else { return date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear(); } } 355 Capítulo 35: Criação de um aplicativo do AIR usando as ferramentas de linha de comando As ferramentas de linha de comando do Adobe® AIR™ permitem que você teste e empacote aplicativos do Adobe AIR. Você também pode usar essas ferramentas em processos de criação automatizados. As ferramentas de linha de comando do AIR estão incluídas no SDK do AIR (http://www.adobe.com/go/learn_air_download_AIRSDK_en). Uso do ADL (AIR Debug Launcher) Use o ADL (AIR Debug Launcher) para executar aplicativos com base em SWF e HTML durante o desenvolvimento. Usando o ADL, você pode executar um aplicativo sem compactá-lo e instalá-lo primeiro. Por padrão, o ADL usa um tempo de execução incluído com o SDK, o que significa que você não precisa instalar o tempo de execução separadamente para usar o ADL. O ADL imprime instruções de rastreamento e erros de tempo de execução para a saída padrão, mas não suporta pontos de interrupção ou outros recursos de depuração. Se estiver desenvolvendo um aplicativo baseado em SWF, use o Flash Debugger (ou Flash CS) para problemas de depuração complexos. É possível conectar-se ao Flash Debugger iniciando o programa depurador antes de executar o aplicativo com ADL. Inicialização de um aplicativo com ADL Use a seguinte sintaxe: adl [-runtime runtime-directory] [-pubid publisher-id] [-nodebug] application.xml [rootdirectory] [-- arguments] -runtime runtime-directory Especifica o diretório que contém o tempo de execução a ser usado. Se não especificado, o diretório do tempo de execução no mesmo SDK do programa ADL é usado. Se você mover o ADL para fora de sua pasta do SDK, deverá especificar o diretório de tempo de execução. No Windows e no Linux, especifique o diretório que contém o diretório do Adobe AIR . No Mac OS X, especifique o diretório que contém a estrutura do Adobe AIR. -pubid publisher-id Atribui o valor especificado como a ID do editor do aplicativo do AIR para essa execução. Especificar uma ID de editor temporária permite que você teste recursos de um aplicativo do AIR, como comunicação por uma conexão local, que usa a ID do editor para ajudar a identificar unicamente um aplicativo. A ID do editor final é determinada pelo certificado digital usado para assinar o arquivo de instalação do AIR. -nodebug Desativa o suporte para depuração. Se usado, o processo de aplicativo não poderá se conectar ao depurador do Flash e as caixas de diálogo para exceções não manipuladas são suprimidas. (No entanto, instruções de rastreamento ainda serão impressas na janela do console.) Desativar a depuração permite que o seu aplicativo seja executado um pouco mais rapidamente e também emula mais rigorosamente o modo de execução de um aplicativo instalado. application.xml O arquivo do descritor do aplicativo. Consulte “Configuração de propriedades do aplicativo do AIR” na página 44. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 356 Criação de um aplicativo do AIR usando as ferramentas de linha de comando root-directory Especifica o diretório raiz do aplicativo a ser executado. Se não especificado, o diretório que contém o arquivo do descritor do aplicativo será usado. -- arguments Qualquer seqüência de caracteres que apareça após "--" é transmitida ao aplicativo como argumentos de linha de comando. Nota: Quando você inicia um aplicativo do AIR já em execução, uma nova instância desse aplicativo não é iniciada. Em vez disso, um evento invoke é despachado para a instância em execução. Impressão de instruções de rastreamento Para imprimir instruções de rastreamento para o console usado para executar o ADL, adicione instruções de rastreamento ao seu código com a função trace(): trace("debug message"); air.trace("debug message"); Exemplos de ADL Execute um aplicativo no diretório atual: adl myApp-app.xml Execute um aplicativo em um subdiretório do diretório atual: adl source/myApp-app.xml release Execute um aplicativo e transmita dois argumentos de linha de comando, "tick" e "tock": adl myApp-app.xml -- tick tock Execute um aplicativo usando um tempo de execução específico: adl -runtime /AIRSDK/runtime myApp-app.xml Execute um aplicativo sem o suporte de depuração: adl myApp-app.xml -nodebug Conexão ao FDB (depurador do Flash) Para depurar um aplicativo do AIR baseado em SWF com o depurador do Flash, inicie uma sessão do FDB e inicie uma versão de depuração do seu aplicativo. Um aplicativo AIR contendo uma versão de depuração de um arquivo SWF se conecta automaticamente a uma sessão de escuta do FDB. Nota: Na versão de depuração de um aplicativo AIR, o arquivo SWF é compilado com o sinalizador -debug. 1 Inicie o FDB. O programa FDB pode ser encontrado no diretório bin do Flex SDK. O console exibe o prompt do FDB: <fdb> 2 Execute o comando run. <fdb>run [Enter] 3 Em um comando diferente ou console do shell, inicie uma versão de depuração do seu aplicativo: adl myApp.xml 4 Usando os comandos do FDB, defina pontos de interrupção como desejado. 5 Digite: continue [Enter] Se um aplicativo AIR for baseado em SWF, o depurador só controlará a execução do código ActionScript. Se o aplicativo do AIR for baseado em HTML, o depurador só controlará a execução do código JavaScript. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 357 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Para executar ADL sem conectar-se ao depurador, inclua a opção -nodebug. adl myApp.xml -nodebug Para obter informações básicas sobre comandos do FDB, execute o comando help: <fdb>help [Enter] Para obter detalhes sobre comandos FDB, consulte Usando os comandos do depurador de linha de comando na documentação do Flex na documentação do Flex. Códigos de erro e saída do ADL A tabela a seguir descreve os códigos de saída impressos pelo ADL: Código de saída Descrição 0 Inicialização bem-sucedida. O ADL é encerrado após o aplicativo do AIR ser encerrado. 1 Invocação bem-sucedida de um aplicativo do AIR já em execução. O ADL é encerrado imediatamente. 2 Erro de uso. Os argumentos fornecidos ao ADL estão incorretos. 3 O tempo de execução não pode ser encontrado. 4 O tempo de execução não pode ser iniciado. Muitas vezes, isso ocorre porque a versão do nível de patch especificado no aplicativo não corresponde à versão ou nível de patch do tempo de execução. 5 Ocorreu um erro de causa desconhecida. 6 O arquivo do descritor do aplicativo não pode ser encontrado. 7 O conteúdo do descritor do aplicativo não é válido. Esse erro normalmente indica que o XML não é bem formado. 8 O principal arquivo de conteúdo do aplicativo (especificado no elemento <content> do arquivo do descritor do aplicativo) não pode ser encontrado. 9 O principal arquivo de conteúdo do aplicativo não é um arquivo SWF ou HTML válido. Empacotamento de um arquivo de instalação do AIR usando o ADT (ferramenta para desenvolvedores do AIR) Você cria um arquivo de instalação do AIR para seus aplicativos do AIR baseados em SWF e em HTML usando o ADT (ferramenta para desenvolvedores do AIR). (Se estiver usando o Adobe Flash CS3 para criar seu aplicativo, também poderá usar o comando Criar arquivo do AIR no menu Comandos para criar o pacote do AIR. Para obter mais informações, consulte “Atualização do Adobe AIR para Flash CS3 Professional” na página 13. Para obter informações sobre o uso do Flash CS4 para criar aplicativos AIR, consulte Publicação no Adobe AIR em Como usar o Flash.) O ADT é um programa Java que você pode executar da linha de comando ou de uma ferramenta de criação como Ant. Os SDKs do AIR e do Flex incluem scripts de linha de comando que executam o programa Java para você. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 358 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Empacotamento de um arquivo de instalação do AIR Cada aplicativo do AIR deve, no mínimo, possuir um arquivo do descritor do aplicativo e um arquivo principal do SWF ou HTML. Qualquer outro ativo de aplicativo instalado deve ser empacotado no arquivo AIR também. Todos os arquivos do instalador do AIR devem ser assinados usando um certificado digital. O instalador do AIR usa a assinatura para verificar que seu arquivo de aplicativo não foi alterado desde que você o assinou. Você pode usar um certificado de assinatura de código de uma autoridade de certificação ou um certificado auto-assinado. Um certificado emitido por uma autoridade de certificação confiável fornece aos usuários do seu aplicativo alguma garantia da sua identidade como editor. Um certificado auto-assinado não pode ser usado para verificar sua identidade como o assinante. Essa desvantagem também enfraquece a garantia de que o pacote não tenha sido alterado, porque um arquivo de instalação legítimo poderia ser substituído por um falsificado antes de ele chegar ao usuário). Você pode empacotar e assinar um arquivo do AIR em uma única etapa usando o comando -package do ADT. Você também pode criar um pacote intermediário, não assinado com o comando -prepare e assinar o pacote intermediário com o comando -sign em uma etapa separada. Ao assinar o pacote de instalação, o ADT automaticamente entra em contato com um servidor de autoridade com carimbo de data/hora para verificar a hora. As informações de carimbo de data/hora estão incluídas no arquivo do AIR. Um arquivo do AIR que inclui um carimbo de data/hora verificado pode ser instalado em qualquer momento do futuro. Se o ADT não puder se conectar ao servidor de carimbo de data/hora, o empacotamento será cancelado. Você pode substituir a opção de carimbo de data/hora, mas sem um carimbo de data/hora, um aplicativo do AIR deixa de poder ser instalado após o certificado usado para assinar o arquivo de instalação expirar. Se estiver criando um pacote If para atualizar um aplicativo do AIR existente, o pacote deverá ser assinado com o mesmo certificado do aplicativo original ou com um certificado que possua a mesma identidade. Para ter a mesma identidade, dois certificados precisam ter o mesmo nome distinto (todos os campos de informações correspondem) e a mesma cadeia de certificados para o certificado raiz. Portanto, você pode usar um certificado renovado de uma autoridade de certificação desde que não altere nenhuma das informações de identificação. No AIR 1.1, você pode migrar um aplicativo para usar um novo certificado usando o comando -migrate. Migrar o certificado requer a assinatura do arquivo do AIR com o novo e o antigo certificado. A migração de certificados permite que você mude de um auto-assinado para um certificado de comercial de assinatura de código ou de um certificado auto-assinado ou comercial para outro. Ao migrar um certificado, seus usuários existentes não precisam desinstalar seu aplicativo existente antes de instalar sua nova versão. Assinaturas de migração possuem carimbo de data/hora, por padrão. Nota: As configurações no arquivo do descritor do aplicativo determinam a identidade de um aplicativo do AIR e seu caminho de instalação padrão. Consulte “A estrutura do arquivo do descritor do aplicativo” na página 44. Empacotamento e assinatura de um arquivo do AIR em uma etapa ❖ Use o comando -package com a seguinte sintaxe (em uma única linha de comando): adt -package SIGNING_OPTIONS air_file app_xml [file_or_dir | -C dir file_or_dir | -e file dir ...] ... SIGNING_OPTIONS As opções de assinatura identificam o armazenamento de chaves que contém a chave privada e o certificado usado para assinar o arquivo do AIR. Para assinar um aplicativo do AIR com um certificado auto-assinado gerado pelo ADT, as opções são: DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 359 Criação de um aplicativo do AIR usando as ferramentas de linha de comando -storetype pkcs12 -keystore certificate.p12 Neste exemplo, certificate.p12 é o nome do arquivo de armazenamento de chaves. (O ADT solicita a você a senha uma vez que ela não é fornecida na linha de comando.) As opções de assinatura são totalmente descritas em “Opções de assinatura de linha de comando do ADT” na página 363. air_file O nome do arquivo do AIR criado. app_xml O caminho para o arquivo do descritor do aplicativo. O caminho pode ser especificado em relação ao diretório atual ou como um caminho absoluto. (O arquivo do descritor do aplicativo é renomeado como “application.xml” no arquivo do AIR.) file_or_dir Os arquivos e diretórios a empacotar no arquivo do AIR. Qualquer número de arquivos e diretórios pode ser especificado, delimitado por um espaço em branco. Se você listar um diretório, todos os arquivos e subdiretórios dentro dele, exceto arquivos ocultos, serão adicionados ao pacote. (Além disso, se o arquivo do descritor do aplicativo for especificado, diretamente ou por caractere curinga ou expansão de diretório, ele será ignorado e não adicionado ao pacote uma segunda vez.) Arquivos e diretórios especificados devem estar no diretório atual ou em um de seus subdiretórios. Use a opção -C para alterar o diretório atual. Importante: Caracteres curinga não podem ser usados nos argumentos file_or_dir depois da opção –C. (Shells de comando expandem os caracteres curinga antes de transmitir os argumentos para o ADT, o que faz com que o ADT procure arquivos no lugar errado.) Você pode, no entanto, usar ainda o caractere de ponto, ".", para representar o diretório atual. Por exemplo, "-C assets ." copia tudo no diretório de ativos, incluindo qualquer subdiretório, para o nível raiz do pacote do aplicativo. -C dir Altera o diretório de trabalho para o valor de dir antes de processar arquivos e diretórios subseqüentes adicionados ao pacote do aplicativo. Os arquivos ou diretórios são adicionados à raiz do pacote do aplicativo. A opção –C pode ser usada quantas vezes for preciso para incluir arquivos de vários pontos no sistema de arquivos. Se um caminho relativo for especificado para dir, o caminho sempre é resolvido do diretório de trabalho original. À medida que o ADT processa os arquivos e diretórios incluídos no pacote, os caminhos relativos entre o diretório atual e os arquivos de destino são armazenados. Esses caminhos são expandidos na estrutura do diretório do aplicativo quando o pacote é instalado. Portanto, especificar -C release/bin lib/feature.swf coloca o arquivo release/bin/lib/feature.swf no subdiretório lib da pasta do aplicativo raiz. -e file dir Coloca o arquivo especificado no diretório do pacote especificado. Nota: O elemento <content> do arquivo do descritor do aplicativo deve especificar o local final do arquivo do aplicativo principal na árvore do diretório do pacote do aplicativo. Exemplos do ADT Arquivos do aplicativo específicos do pacote no diretório atual: adt –package -storetype pkcs12 -keystore cert.p12 myApp.air myApp.xml myApp.swf components.swc Empacote todos os arquivos e subdiretórios no diretório de trabalho atual: adt –package -storetype pkcs12 -keystore ../cert.p12 myApp.air myApp.xml . Nota: O arquivo de armazenamento de chaves contém a chave privada usada para assinar seu aplicativo. Nunca inclua o certificado de assinatura no pacote do AIR! Se você usar caracteres curinga no comando do ADT, coloque o arquivo de armazenamento de chaves em um local diferente para que ele não seja incluído no pacote. Neste exemplo, o arquivo de armazenamento de chaves, cert.p12, reside no diretório pai. Empacote apenas os arquivos principais e um subdiretório de imagens: adt –package -storetype pkcs12 -keystore cert.p12 myApp.air myApp.xml myApp.swf images DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 360 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Empacote o arquivo application.xml e o SWF principal localizados em um diretório de trabalho (release/bin): adt –package -storetype pkcs12 -keystore cert.p12 myApp.air release/bin/myApp.xml –C release/bin myApp.swf Empacote ativos de mais de um lugar no seu sistema de arquivo de criação. Neste exemplo, os ativos do aplicativo são localizados nas seguintes pastas antes do empacotamento: /devRoot /myApp /release /bin myApp.xml myApp.swf /artwork /myApp /images image-1.png ... image-n.png /libraries /release /libs lib-1.swf ... lib-n.swf AIRAliases.js Executar o seguinte comando do ADT do diretório /devRoot/myApp: adt –package -storetype pkcs12 -keystore cert.p12 myApp.air release/bin/myApp.xml –C release/bin myApp.swf –C ../artwork/myApp images –C ../libraries/release libs Resulta na seguinte estrutura de pacote: /myAppRoot /META-INF /AIR application.xml hash myApp.swf mimetype /images image-1.png ... image-n.png /libs lib-1.swf ... lib-n.swf AIRAliases.js Execute o ADT como um programa Java (sem definir o caminho da classe): java –jar {AIRSDK}/lib/ADT.jar –package -storetype pkcs12 -keystore cert.p12 myApp.air myApp.xml myApp.swf Execute o ADT como um programa Java (com o caminho da classe Java definido para incluir o pacote ADT.jar): DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 361 Criação de um aplicativo do AIR usando as ferramentas de linha de comando java com.adobe.air.ADT –package -storetype pkcs12 -keystore cert.p12 myApp.air myApp.xml myApp.swf Mensagens de erro do ADT As tabelas a seguir listam os erros que o programa ADT pode reportar e suas possíveis causas: Erros de validação do descritor do aplicativo Código do erro Descrição Observações 100 Não é possível analisar o descritor do aplicativo Verifique o arquivo do descritor do aplicativo para obter os erros de sintaxe XML, como tags abertas. 101 Espaço para nomes ausente Adicione o espaço para nomes ausente. 102 Espaço para nomes inválido Verifique a ortografia do espaço para nomes. 103 Elemento ou atributo inesperado Remova os elementos e atributos incorretos. Valores personalizados não são permitidos no arquivo de descritor. Verifique a ortografia dos nomes do elemento e dos atributos. Verifique se os elementos estão inseridos no elemento pai correto e se os atributos são usados com os elementos corretos. 104 Elemento ou atributo ausente Adicione o elemento ou atributo necessário. 105 Elemento ou atributo contém um valor inválido Corrija o valor incorreto. 106 Combinação de atributos de janela ilegal Não é possível usar algumas configurações de janela, como transparency = true e systemChrome = standard juntas. Altere uma das configurações incompatíveis. 107 O tamanho mínimo da janela é maior que o Altere a configuração do tamanho mínimo tamanho máximo da janela ou do máximo. Consulte “Configuração de propriedades do aplicativo do AIR” na página 44 para obter informações sobre espaços para nomes, elementos, atributos e seus valores válidos. Erros do ícone do aplicativo DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 362 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Código do erro Descrição Observações 200 Não é possível abrir o arquivo de ícone Verifique se o arquivo existe no caminho especificado. Use outro aplicativo para garantir que o arquivo possa ser aberto. 201 Ícone no tamanho errado O tamanho do ícone (em pixels) deve corresponder à tag XML. Por exemplo, dado o elemento do descritor do aplicativo: <image32x32>icon.png</image32x3 2> A imagem em icon.png deve ser exatamente de 32x32 pixels. 202 O arquivo do ícone contém um formato de Somente o formato PNG tem suporte. imagem sem suporte Converta imagens em outros formatos antes de empacotar o aplicativo. Erros de arquivo no aplicativo Código do erro Descrição Observações 300 Arquivo ausente ou não é possível abrir arquivo Não é possível encontrar ou abrir um arquivo especificado na linha de comando. 301 Arquivo do descritor de aplicativo ausente ou não é possível abri-lo O arquivo do descritor de aplicativo não foi encontrado no caminho especificado ou não é possível abri-lo. 302 Arquivo do conteúdo raiz ausente do pacote É necessário adicionar o arquivo SWF ou HTML referenciado no elemento <content> do descritor do aplicativo ao pacote incluindo-o nos arquivos listados na linha de comando do ADT. 303 Arquivo de ícone ausente do pacote É necessário adicionar os arquivos de ícone especificados no descritor do aplicativo ao pacote incluindo-os entre os arquivos listados na linha de comando do ADT. Os arquivos de ícone não são adicionados automaticamente. 304 Conteúdo da janela inicial inválido O arquivo referenciado no elemento <content> do descritor do aplicativo não é reconhecido como arquivo HTML ou SWF válido. 305 A versão inicial do SWF de conteúdo da janela excedeu a versão do espaço para nomes Códigos de saída de outros erros A versão SWF do arquivo referenciado no elemento <content> do descritor do aplicativo não tem suporte da versão do AIR especificado no espaço para nomes do descritor. Por exemplo, se você tentar empacotar um arquivo SWF10 (Flash Player 10) como conteúdo inicial de um aplicativo AIR 1.1, gerará esse erro. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 363 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Código de saída Descrição Observações 2 Erro de uso Verifique se há erros nos argumentos da linha de comando 5 Erro desconhecido Esse erro indica que não é possível explicar uma situação com condições de erro comuns. As possíveis causas raiz incluem incompatibilidade entre o ADT e o Java Runtime Environment, instalações de ADT ou JRE corrompidas e erros de programação dentro do ADT. 6 Não foi possível gravar no diretório de saída Verifique se o diretório de saída especificado (ou implícito) está acessível e se a unidade que o contém tem espaço em disco suficiente. 7 Não foi possível acessar o certificado Verifique se o caminho para o armazenamento de chaves está especificado corretamente. Verifique se o certificado do armazenamento de chaves pode ser acessado. O utilitário Java 1.6 Keytool pode ser usado para ajudar a solucionar problemas de acesso ao certificado. 8 Certificado inválido O arquivo de certificado foi malformado, modificado, expirado ou revogado. 9 Não foi possível assinar o arquivo AIR Verifique as opções de assinaturas enviadas para o ADT. 10 Não foi possível criar um carimbo de data e O ADT não estabeleceu uma conexão com hora o servidor do carimbo de data e hora. Se você se conecta à Internet por meio de um servidor proxy, pode precisar definir as configurações de proxy do JRE. 11 Erro de criação do certificado Verifique os argumentos da linha de comando usados para criar assinaturas. 12 Entrada inválida Verifique os caminhos e outros argumentos enviados para o ADT na linha de comando. Opções de assinatura de linha de comando do ADT O ADT usa JCA (arquitetura de criptografia Java) para acessar chaves privadas e certificados para assinar aplicativos do AIR. As opções de assinatura identificam o armazenamento de chaves e a chave privada e o certificado dentro desse armazenamento de chaves. O armazenamento de chaves deve incluir a chave privada e a cadeia de certificado associada. A cadeia de certificado é usada para estabelecer a ID do editor do aplicativo. Se o certificado de assinatura estiver vinculado a um certificado confiável em um computador, o nome comum do certificado será exibido como o nome do editor na caixa de diálogo de instalação do AIR. O ADT requer que o certificado esteja em conformidade com o padrão x509v3 (RFC3280) e inclua a extensão de uso de chave estendida com os valores adequados para assinatura do código. As restrições no certificado são respeitadas e poderiam impedir o uso de alguns certificados para assinar aplicativos do AIR. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 364 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Nota: O ADT usa as configurações de proxy do ambiente de tempo de execução Java, quando apropriado, para conectar aos recursos de Internet para verificar listas de revogação de certificado e obter carimbos de data/hora. Se encontrar problemas para se conectar a recursos da Internet ao usar o ADT e sua rede exigir configurações de proxy específicas, você pode precisar configurar as configurações de proxy do JRE. Especificação de opções de assinatura do AIR ❖ Para especificar as opções de assinatura do ADT para os comandos -package e -prepare, use a seguinte sintaxe: [-alias aliasName] [-storetype type] [-keystore path] [-storepass password1] [-keypass password2] [-providerName className] [-tsa url] -alias aliasName —O alias de uma chave no armazenamento de chaves. Especificar um alias não é necessário quando um armazenamento de chaves contém apenas um único certificado. Se nenhum alias for especificado, o ADT usará a primeira chave do armazenamento de chaves. Nem todos os aplicativos de gerenciamento do armazenamento de chaves permitem que um alias seja atribuído a certificados. Ao usar o armazenamento de chaves do sistema Windows, por exemplo, use o nome distinto do certificado como o alias. Você pode usar o utilitário Java Keytool para listar os certificados disponíveis para que possa determinar o alias. Por exemplo, executar o comando: keytool -list -storetype Windows-MY produz uma saída como a seguinte para um certificado: CN=TestingCert,OU=QE,O=Adobe,C=US, PrivateKeyEntry, Certificate fingerprint (MD5): 73:D5:21:E9:8A:28:0A:AB:FD:1D:11:EA:BB:A7:55:88 Para se referir a esse certificado na linha de comando do ADT, defina o alias como: CN=TestingCert,OU=QE,O=Adobe,C=US No Mac OS X, o alias de um certificado no Keychain é o nome exibido no aplicativo Keychain Access. -storetype type —O tipo de armazenamento de chaves, determinado pela implementação de armazenamento de chaves. A implementação de armazenamento de chaves padrão incluída na maioria das instalações de Java suporta os tipos JKS e PKCS12. O Java 5.0 inclui suporte para o tipo PKCS11, para acessar armazenamentos de chaves em tokens de hardware e para o tipo Keychain, para acessar o chaveiro do Mac OS X. O Java 6.0 inclui suporte para o tipo MSCAPI (no Windows). Se outros provedores de JCA tiverem sido instalados e configurados, tipos adicionais de armazenamentos de chaves podem estar disponíveis. Se nenhum tipo de armazenamento de chave for especificado, o tipo padrão para o provedor de JCA padrão será usado. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 365 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Tipo de armazenament o Formato de armazenamento de chave Versão mínima de Java JKS Arquivo de armazenamento de chave Java (.keystore) 1.2 PKCS12 Arquivo PKCS12 (.p12 ou .pfx) 1.4 PKCS11 Token de hardware 1.5 KeychainStore Chaveiro do Mac OS X 1.5 Windows-MY ou Windows-ROOT MSCAPI 1.6 -keystore path —O caminho para o arquivo de armazenamento de chaves para tipos de armazenamento baseado em arquivo. -storepass password1 —A senha necessária para acessar o armazenamento de chaves. Se não especificada, o ADT solicita a senha. -keypass password2 —A senha necessária para acessar a chave privada usada para assinar o aplicativo do AIR. Se não especificada, o ADT solicita a senha. -providerName className —O provedor de JCA para o tipo de armazenamento de chave especificado. Se não especificado, o ADT usa o provedor padrão para esse tipo de armazenamento de chave. -tsa url —Especifica a URL de um servidor com carimbo de data/hora compatível com RFC3161 para carimbar com data/hora a assinatura digital. Se nenhuma URL for especificada, um servidor padrão com carimbo de data/hora fornecido pela Geotrust será usado. Quando a assinatura de um aplicativo do AIR for carimbada com data/hora, o aplicativo poderá ainda ser instalado depois que o certificado de assinatura expirar, porque o carimbo de data/hora verifica se o certificado era válido no momento da assinatura. Se o ADT não puder se conectar ao servidor de carimbo de data/hora, a assinatura será cancelada e nenhum empacotamento será produzido. Especifique -tsa none para desabilitar o carimbo de data/hora. No entanto, um aplicativo do AIR empacotado sem um carimbo de data/hora deixa de poder ser instalado depois que o certificado de assinatura expira. Nota: As opções de assinatura são como as opções equivalentes do utilitário Java Keytool. Você pode usar o utilitário Keytool para examinar e gerenciar armazenamentos de chaves no Windows. O utilitário de segurança da Apple® também pode ser usado para esse fim no Mac OS X. Exemplos de opção de assinatura Assinatura com um arquivo .p12: -storetype pkcs12 -keystore cert.p12 Assinatura com o armazenamento de chaves Java padrão: -alias AIRcert -storetype jks Assinatura com o armazenamento de chaves Java específico: -alias AIRcert -storetype jks -keystore certStore.keystore Assinatura com o chaveiro do Mac OS X: -alias AIRcert -storetype KeychainStore -providerName Apple DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 366 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Assinatura com o armazenamento de chaves do sistema Windows: -alias cn=AIRCert -storeype Windows-MY Assinatura com um token de hardware (consulte as instruções do fabricante do token sobre como configurar Java para usar o token e para o valor correto de providerName): -alias AIRCert -storetype pkcs11 -providerName tokenProviderName Assinatura sem incorporar um carimbo de data/hora: -storetype pkcs12 -keystore cert.p12 -tsa none Criação de um arquivo intermediário do AIR não assinado com o ADT Use o comando -prepare para criar um arquivo intermediário do AIR não assinado. Um arquivo intermediário do AIR deve ser assinado com o comando do ADT -sign para produzir um arquivo de instalação do AIR válido. O comando -prepare emprega os mesmos sinalizadores e parâmetros do comando -package (exceto para as opções de assinatura). A única diferença é que o arquivo de saída não é assinado. O arquivo intermediário é gerado com a extensão de nome de arquivo: airi. Para assinar um arquivo intermediário do AIR, use o comando do ADT -sign. (Consulte Assinatura de um arquivo intermediário do AIR com o ADT.) Exemplo do ADT adt –prepare unsignedMyApp.airi myApp.xml myApp.swf components.swc Assinatura de um arquivo intermediário do AIR com o ADT Para assinar um arquivo intermediário do AIR com o ADT, use o comando -sign. O comando sign funciona apenas com arquivos intermediários do AIR (extensão airi). Um arquivo do AIR não pode ser assinado uma segunda vez. Para criar um arquivo intermediário do AIR, use o comando do ADT -prepare. (Consulte “Criação de um arquivo intermediário do AIR não assinado com o ADT” na página 366.) Assinatura de um arquivo AIRI ❖ Use o comando do ADT -sign com a seguinte sintaxe: adt -sign SIGNING_OPTIONSairi_fileair_file SIGNING_OPTIONS As opções de assinatura identificam a chave privada e o certificado com o qual o arquivo do AIR será assinado. Essas opções são descritas em “Opções de assinatura de linha de comando do ADT” na página 363. airi_file O caminho para o arquivo intermediário não assinado do AIR a ser assinado. air_file O nome do arquivo do AIR a ser criado. Exemplo do ADT adt –sign -storetype pkcs12 -keystore cert.p12 unsignedMyApp.airi myApp.air Para obter mais informações, consulte “Assinatura digital de um arquivo do AIR” na página 321. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 367 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Assinatura de um arquivo do AIR para alterar o certificado do aplicativo Para atualizar um aplicativo do AIR existente para usar um novo certificado de assinatura, use o comando do ADT migrate. A migração de certificados pode ser útil nas seguintes situações: • Atualização de um certificado auto-assinado para um emitido por uma autoridade de certificação • Alteração de um certificado auto-assinado que está prestes a expirar para um novo certificado auto-assinado • Alterar de um certificado comercial para outro, por exemplo, quando sua identidade corporativa for alterada Para aplicar uma assinatura de migração, o certificado original ainda deve estar válido. Depois que o certificado tiver expirado, uma assinatura de migração não poderá ser aplicada. Usuários do seu aplicativo precisarão desinstalar a versão existente antes que possam instalar a versão atualizada. Observe que a assinatura de migração possui carimbo de data/hora, por padrão, então as atualizações do AIR assinadas com uma assinatura de migração permanecerão válidas mesmo depois que o certificado expirar. Nota: Você não precisa normalmente migrar o certificado quando renovar um certificado emitido comercialmente. Um certificado renovado retém a mesma identidade do editor do original, a menos que o nome distinto tenha sido alterado. Para obter uma lista completa dos atributos do certificado usados para determinar o nome distinto, consulte “Sobre identificadores do editor do AIR” na página 322. Para migrar o aplicativo a fim de usar um novo certificado: 1 Crie uma atualização para o seu aplicativo 2 Empacote e assine o arquivo de atualização do AIR com o novo certificado 3 Assine o arquivo do AIR novamente com o certificado original usando o comando -migrate Um arquivo do AIR assinado com o comando -migrate pode ser usado para instalar uma nova versão do aplicativo e para atualizar versões anteriores, incluindo as assinadas com o certificado antigo. Migração de um aplicativo do AIR para usar um novo certificado ❖ Use o comando do ADT -migrate com a seguinte sintaxe: adt -migrate SIGNING_OPTIONS air_file_in air_file_out SIGNING_OPTIONS As opções de assinatura identificam a chave privada e o certificado com o qual o arquivo do AIR será assinado. Essas opções devem identificar o certificado de assinatura original e são descritas em “Opções de assinatura de linha de comando do ADT” na página 363. air_file_in O arquivo do AIR para a atualização, assinado com o certificado novo. air_file_out O arquivo do AIR a ser criado. Exemplo do ADT adt –migrate -storetype pkcs12 -keystore cert.p12 myApp.air myApp.air Para obter mais informações, consulte “Assinatura digital de um arquivo do AIR” na página 321. Nota: O comando -migrate foi adicionado ao ADT na versão AIR 1.1. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 368 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Criação de um certificado auto-assinado com o ADT Os certificados auto-assinados permitem que você produza um arquivo de instalação do AIR válido, mas apenas fornecem garantias de segurança limitadas aos seus usuários uma vez que a autenticidade de certificados autoassinados não pode ser verificada. Quando um arquivo do AIR auto-assinado é instalado, as informações do editor são exibidas para o usuário como Desconhecidas. Um certificado gerado pelo ADT é válido por cinco anos. Se você criar uma atualização para um aplicativo do AIR assinada com um certificado auto-gerado, deverá usar o mesmo certificado para assinar os originais e atualizar os arquivos do AIR. Os certificados que o ADT produz são sempre únicos, mesmo se os mesmos parâmetros são usados. Portanto, se você desejar auto-assinar atualizações com um certificado gerado pelo ADT, preserve o certificado original em um local seguro. Além disso, você não poderá produzir um arquivo do AIR atualizado depois que o certificado original gerado pelo ADT expirar. (Você pode publicar novos aplicativos com um certificado diferente, mas não novas versões do mesmo aplicativo.) Importante: Devido às limitações de certificados auto-assinados, a Adobe recomenda altamente o uso de um certificado comercial emitido por uma autoridade de certificação de reputação, para assinar publicamente aplicativos do AIR lançados. O certificado e a chave privada associada gerados pelo ADT são armazenados em um arquivo de armazenamento de chaves do tipo PKCS12. A senha especificada é definida na chave em si, e não no armazenamento de chaves. Geração de um certificado de ID digital para auto-assinar arquivos do AIR ❖ Use o comando do ADT -certificate (em uma única linha de comando): adt -certificate -cn name [-ou org_unit][-o org_name][-c country] key_type pfx_file password -cn name A seqüência de caracteres atribuída como o nome comum do novo certificado. -ou org_unit Uma seqüência de caracteres atribuída como a unidade organizacional que emite o certificado. (Opcional.) -o org_name Uma seqüência de caracteres atribuída como a organização que emite o certificado. (Opcional.) -c countryUm código de país de duas letras ISO-3166. Um certificado não é gerado se um código inválido é fornecido. (Opcional.) key_typeO tipo de chave a ser usada para o certificado, “1024-RSA” ou “2048-RSA”. pfx_file O caminho para o arquivo do certificado a ser gerado. password A senha para o novo certificado. A senha é necessária ao assinar arquivos do AIR com esse certificado. Exemplos de geração de certificado adt -certificate -cn SelfSign -ou QE -o "Example, Co" -c US 2048-RSA newcert.p12 39#wnetx3tl adt -certificate -cn ADigitalID 1024-RSA SigningCert.p12 39#wnetx3tl Para usar esses certificados para assinar arquivos do AIR, você usa as seguintes opções de assinatura com os comandos -package ou -prepare do ADT: -storetype pkcs12 -keystore newcert.p12 -keypass 39#wnetx3tl -storetype pkcs12 -keystore SigningCert.p12 -keypass 39#wnetx3tl DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 369 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Uso do Apache Ant com as ferramentas do SDK Esse tópico fornece exemplos de como usar a ferramenta de criação Apache Ant para testar e empacotar aplicativos do AIR. Nota: Essa discussão não tenta fornecer um resumo abrangente do Apache Ant. Para obter a documentação do Ant, consulte http://Ant.Apache.org. Uso do Ant para projetos simples Esse exemplo ilustra a criação de um aplicativo do AIR usando o Ant e as ferramentas de linha de comando do AIR. Uma estrutura de projeto simples é usada com todos os arquivos armazenados em um único diretório. Para facilitar a reutilização do script de criação, esses exemplos usam várias propriedades definidas. Um conjunto de propriedades identifica os locais instalados das ferramentas de linha de comando: <property name="SDK_HOME" value="C:/Flex3SDK"/> <property name="ADL" value="${SDK_HOME}/bin/adl.exe"/> <property name="ADT.JAR" value="${SDK_HOME}/lib/adt.jar"/> O segundo conjunto de propriedades é específico do projeto. Essas propriedades supõem uma convenção de nomenclatura na qual o descritor do aplicativo e os arquivos do AIR são baseados em nome no arquivo de origem raiz. Outras convenções são facilmente suportadas. <property <property <property <property <property <property name="APP_NAME" value="ExampleApplication"/> name="APP_ROOT" value="."/> name="APP_DESCRIPTOR" value="${APP_ROOT}/${APP_NAME}-app.xml"/> name="AIR_NAME" value="${APP_NAME}.air"/> name="STORETYPE" value="pkcs12"/> name="KEYSTORE" value="ExampleCert.p12"/> Invocação do ADL para testar um aplicativo Para executar o aplicativo com o ADL, use uma tarefa exec: <target name="test" depends="compile"> <target name="test"> <exec executable="${ADL}"> <arg value="${APP_DESCRIPTOR}"/> </exec> </target> Invocação do ADT para empacotar um aplicativo Para empacotar o aplicativo, use uma tarefa Java para executar a ferramenta adt.jar: <target name="package"> <java jar="${ADT.JAR}" fork="true" failonerror="true"> <arg value="-package"/> <arg value="-storetype"/> <arg value="${STORETYPE}"/> <arg value="-keystore"/> <arg value="${KEYSTORE}"/> <arg value="${AIR_NAME}"/> <arg value="${APP_DESCRIPTOR}"/> <arg value="${APP_NAME}.swf"/> <arg value="*.png"/> </java> </target> DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 370 Criação de um aplicativo do AIR usando as ferramentas de linha de comando Se seu aplicativo tiver mais arquivos para empacotar, você pode adicionar elementos <arg> adicionais. Uso do Ant para projetos mais complexos A estrutura do diretório de um aplicativo típico é mais complexa do que um diretório único. O exemplo a seguir ilustra um arquivo de criação usado para compilar, testar e empacotar um aplicativo do AIR com uma estrutura de diretório de projeto mais prática. Esse projeto de exemplo armazena os arquivos de origem do aplicativo e outros ativos como arquivos de ícone em um diretório src. O script de criação cria os seguintes diretórios de trabalho: build Armazena as versões de lançamento (não-depuração) de arquivos do SWF compilados. debug Armazena a versão de depuração não empacotada do aplicativo, incluindo qualquer arquivo de ativo e SWFs compilados. O utilitário do ADL executa o aplicativo desse diretório. release Armazena o pacote do AIR final As ferramentas do AIR requerem o uso de algumas opções adicionais ao operar em arquivos fora do diretório de trabalho atual: Teste O segundo argumento transmitido ao ADL especifica o diretório raiz do aplicativo do AIR. Para especificar o diretório raiz do aplicativo, a seguinte linha é adicionada à tarefa de teste: <arg value="${debug}"/> Empacotamento Empacotar arquivos de subdiretórios que não devem ser parte da estrutura do pacote final requer o uso da diretiva -C para alterar o diretório de trabalho do ADT. Quando você usa a diretiva -C, os arquivos e diretórios no novo diretório de funcionamento são copiados para o nível raiz do arquivo do pacote do AIR. Portanto, -C build file.png copia file.png para a raiz do diretório do aplicativo. Da mesma forma, -C assets icons copia a pasta icon para o nível raiz e copia também todos os arquivos e diretórios dentro da pasta icons. Por exemplo, a seguinte seqüência de linhas na tarefa do pacote adiciona o diretório icons diretamente ao nível raiz do arquivo do pacote do aplicativo: <arg value="-C"/> <arg value="${assets}"/> <arg value="icons"/> Nota: Se você precisar mover vários recursos e ativos para diferentes locais relativos, é normalmente mais fácil dispô-los em um diretório temporário usando tarefas do Ant do que criar uma lista de argumento complexa para o ADT. Depois que seus recursos forem organizados, uma simples lista de argumento do ADT poderá ser usada para empacotá-los. DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 371 Criação de um aplicativo do AIR usando as ferramentas de linha de comando <project> <!-- SDK properties --> <property name="SDK_HOME" value="C:/Flex3SDK"/> <property name="ADL" value="${SDK_HOME}/bin/adl.exe"/> <property name="ADT.JAR" value="${SDK_HOME}/lib/adt.jar"/> <!-- Project properties --> <property name="PROJ_ROOT_DIR" value="."/> <property name="APP_NAME" value="ExampleApplication"/> <property name="APP_ROOT_DIR" value="."/> <property name="APP_ROOT_FILE" value="${APP_NAME}.swf"/> <property name="APP_DESCRIPTOR" value="${PROJ_ROOT_DIR}/${APP_NAME}-app.xml"/> <property name="AIR_NAME" value="${APP_NAME}.air"/> <property name="release" location="${PROJ_ROOT_DIR}/release"/> <property name="assets" location="${PROJ_ROOT_DIR}/src/assets"/> <property name="STORETYPE" value="pkcs12"/> <property name="KEYSTORE" value="ExampleCert.p12"/> <target name="init" depends="clean"> <mkdir dir="${release}"/> </target> <target name="test"> <exec executable="${ADL}"> <arg value="${APP_DESCRIPTOR}"/> <arg value="${APP_ROOT_DIR}"/> </exec> </target> <target name="package" depends="init"> <java jar="${ADT.JAR}" fork="true" failonerror="true"> <arg value="-package"/> <arg value="-storetype"/> <arg value="${STORETYPE}"/> <arg value="-keystore"/> <arg value="${KEYSTORE}"/> <arg value="${release}/${AIR_NAME}"/> <arg value="${APP_DESCRIPTOR}"/> <arg value="-C"/> <arg value="${APP_ROOT_DIR}"/> <arg value="${APP_ROOT_FILE}"/> <arg value="-C"/> <arg value="${assets}"/> <arg value="icons"/> </java> </target> <target name="clean" description="clean up"> <delete dir="${release}"/> </target> </project> 372 Índice Símbolos : caractere (dois pontos), em nomes de parâmetro de instrução SQL 175 distribuição 312 arquivos Info.plist (Mac OS) 49 execução 312, 320 arquivos P12 322 ícones 51 arquivos PFX 322 ? (ponto de interrogação) caractere, em parâmetros SQL sem nome 176 informações de copyright 49 arquivos SWF Numéricos 1024-RSA 368 2048-RSA 368 inicializar 291 carregamento por tag de script 244 instalação 23, 312 arquivos temporários 121 invocação 291 arrastar e soltar invocação do navegador 52 classes relacionadas a 133 sair 291 comportamento padrão em HTML 141 versões 47, 300, 329 efeitos de cursor 139, 143 A AC_RuntimeActiveContent.js 314 AppInstallDisabled (configuração de Registro do Windows) 26 eventos em HTML 141 Acrobat 219, 272 área de transferência gestos 133 ActionScript entre scripts JavaScript 241 copiar e colar 149 formatos de transferência 133 HTML 140, 224 argumentos de linha de comando, captura 292 para conteúdo de caixa de proteção de não-aplicativo (em HTML) 147 atualização 23 armazenamentos de chaves 363, 368 suporte a Flex 135 desinstalação 2 arquivo AIRAliases.js 218, 239 instalação 23 Arquivo AIRLocalizer.js 344 assinatura de arquivos do AIR 358 introdução 6 arquivo ApplicationUpdater_UI.swf 333 assinatura de código 43, 321 nova funcionalidade 54 Arquivo ApplicationUpdater.swc 332 assinaturas Adobe AIR teclas do modificador 139 Adobe Media Player 277 Arquivo ApplicationUpdater.swf 333 Adobe Reader 219, 272 arquivo ApplicatoinUpdater_UI.swc 332 assinaturas digitais 321, 358, 363 AIR Debug Launcher (ADL) arquivo de configuração de atualização (estrutura de atualização) 336 associações de tipo de arquivo 52, 293, 299 códigos de erro e saída 357 Ajax segurança 33 suporte na caixa de proteção do aplicativo 33 arquivo de descrição de atualização (estrutura de atualização) 335 arquivo descritor do aplicativo leitura 298 migração 325, 367 atalhos do teclado copiar e colar 151 ativação de janelas 67, 73 atividade (usuário), detecção 300 AMF (Action Message Format) 135, 154, 157 arquivo do descritor do aplicativo 44 atividade de usuário, detecção 300 arquivo publisherid 298 aparência de janelas 62 arquivos atributo allowCrossDomainXHR (elementos frame e iframe) 222, 227 API de arquivo 106 banco de dados 165 API de sistema de arquivos 106 cópia 119 aplicativos exclusão 120 atributo contenteditable (HTML) 145 atributo documentRoot (elementos frame e iframe) 30, 219, 227, 248 gravação 121 atributo minimumPatchLevel (arquivo do descritor do aplicativo) 45 aplicativos avançados da Internet (RIAs) 6 leitura 121 Atributo ondominitialize 228 aplicativos de amostra 2 movimentação 119 aplicativos do AIR referência 110 atributo sandboxRoot (elementos frame e iframe) 219, 222, 227, 248 Consulte aplicativos do AIR associações de tipo arquivo 299 associações de tipo de arquivo 52, 293 atualização 23, 52, 328 caminho de instalação 47 configurações 44, 47, 298 desinstalação 26 detecção de instalação de 318 suporte a arrastar e soltar 133 suporte a copiar e colar 149 arquivos AIRI criação com a ferramenta para desenvolvedores do AIR (ADT) 366 arquivos do AIR assinatura 321 empacotamento 358 atributos documentRoot (elementos frame e iframe) 30 atualização de aplicativos do AIR 52, 328 autoridades de certificação (CAs) 321 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 373 Índice caixas de proteção que não são de aplicativo 219 método uncompress() 157 alteração de dados 185 caixas de proteção remotas 27, 220 método writeFloat() 154 arquivos 165 caminhos (arquivo e diretório) 112 método writeInt() 154 campos 166 caminhos relativos (entre arquivos) 113 método writeObject() 154 chaves primárias 184, 185 caminhos, relativo 113 método writeUTFBytes() 154 classes usadas com 167 campo NSHumanReadableCopyright (Mac OS) 49 propriedade bytesAvailable 155 B bancos de dados colunas 166 conexão 172 campos (banco de dados) 166 criação 169 caractere @, em nomes de parâmetro de instrução SQL 175 desempenho 176 caracteres mnemônicos digitação de dados 176, 189 itens de menu 90 método writeBytes() 154 propriedade length 155 propriedade position 155 classe Capabilities propriedade playerType 300 classe Clipboard erros 186 carimbos de data/hora 323 estrutura 166 Centro de desenvolvedores do Adobe Acrobat 273 classe CompressionAlgorithm 157 exclusão de dados 185 identificadores de linha 185 certificados classe ContextMenuEvent método getData() 135, 139 Classe ContextMenu 89, 92 linhas 166 alteração 325, 367 modo assíncrono 168 assinatura de arquivos do AIR 321 modo síncrono 168 assinatura de código 43 Classe ContextMenuItem 89 na memória 169 autorizações (CAs) 43 classe Dictionary 239 recuperação de dados 177 cadeias 326 classe DRMAuthenticateEvent 278, 285 segurança 176 expiração de 323 classe DRMErrorEvent 278 sobre 165 formatos de 322 tabelas 166, 170 migração 325, 367 usos de 165 opções de linha de comando do ADT 363 vários, trabalhar com 186 bancos de dados locais Consulte bancos de dados propriedade contextMenuOwner 92 propriedade mouseTarget 92 códigos de erro 286 propriedade subErrorID 286 classe DRMStatusEvent 278 certificados auto-assinados 43, 321, 368 classe EncryptedLocalStore 215 Certificados ChosenSecurity 321, 323 Classe File 106, 107 Certificados do desenvolvedor Apple 323 getRootDirectories() 107 bancos de dados na memória 169 Certificados do desenvolvedor do AIR 323 método getRootDirectories() 107 bancos de dados relacionais Certificados do desenvolvedor JavaSoft 323 método resolvePath() 107 Certificados GlobalSign 321, 323 Consulte bancos de dados barra de ferramentas (Mac OS) 65 Certificados Microsoft Authenticode 323 propriedade applicationStorageDirectory 107 barras de menu 88 certificados Thawte 321, 323 propriedade desktopDirectory 107 bitmaps Certificados VeriSign 323 propriedade documentsDirectory 107 suporte a arrastar e soltar 133, 142 certificados Verisign 321, 323 propriedade nativePath 107, 118 suporte a copiar e colar 149 Chaveiro (associação de dados criptografados com usuários) 215 propriedade spaceAvailable 115 propriedade url 107, 118 propriedade userDirectory 107 C caixa de proteção confiável local 220 chaves primárias caixa de proteção do aplicativo 27, 219, 220, 233, 234, 235, 238, 248, 300 chaves privadas 363 classe ApplicationDomain 242 fazendo referência a um banco de dados local 169 caixa de proteção local com rede 27 classe BrowserInvokeEvent 294 método browseForDirectory() 110 caixa de proteção local com sistema de arquivos 27, 220 classe ByteArray método browseForOpen() 111 bancos de dados 184 classe File construtor 154 método browseForSave() 111 caixa de proteção local confiável 27 método compress() 157 método copyTo() 119 caixas de diálogo seletoras de arquivos 111 método readBytes() 154 método copyToAsync() 119 caixas de diálogo seletoras de diretórios 110 método readFloat() 154 método createDirectory() 116 caixas de proteção 27, 220, 248, 300 método readInt() 154 método createTempDirectory() 116, 121 caixas de proteção "não-aplicativos" 29 método readObject() 154 método createTempFile() 121 caixas de proteção de não-aplicativos 147, 220, 234, 235, 248 método readUTFBytes() 154 método deleteDirectory() 118 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 374 Índice método deleteDirectoryAsync() 118 classe InvokeEvent 53, 292 método deleteFile() 120 propriedade currentDirectory 292 método deleteFileAsync() 120 propriedade de argumentos 292 propriedade label 152 propriedade mnemonicIndex 90 propriedade submenu 88 método getDirectoryListingAsync() 117 classe Keyboard 89 método load() 129 Classe Loader 68 acesso JavaScript a 218 método moveTo() 119 Classe LoaderContext construtor 67 método moveToAsync() 119 método moveToTrash() 120 método moveToTrashAsync() 120 propriedade allowLoadBytesCodeExecution 41 classe LoaderContext classe NativeWindow 59 eventos 79 instanciação 71 método activate 73 método relativize() 113 propriedade applicationDomain 36 método activate() 73 método save() 129 propriedade securityDomain 36 método addEventListener() 79 propriedade creationDate 118 classe LoaderInfo método close(). 74 propriedade creator 118 propriedade childSandboxBridge 36 método dispatchEvent() 61 propriedade encoding 115 propriedade parentSandboxBridge 36 método maximize() 75 propriedade exists 118 classe LocalConnection 314, 321 método minimize() 75 propriedade isDirectory 118 classe NativeApplication 227 método orderBehind() 73 propriedade lineEnding 115 método addEventListener() 291 método orderInBackOf() 73 propriedade modificationDate 118 método exit() 296 método orderInFrontOf() 73 propriedade name 118 método getDefaultApplication() 299 método orderToBack() 73 propriedade parent 118 método isSetAsDefaultApplication() 299 método orderToFront() 73 propriedade separator 115 método removeAsDefaultApplication() 299 método restore() 75 propriedade size 118 propriedade type 118 Classe FileMode 106 classe FileReference método load() 129 método save() 129 Classe FileStream 106 Classe HTMLLoader 233 classe HTMLLoader acesso JavaScript a 218 eventos 252 método createRootWindow() 67, 69, 233 método loadString() 35, 233 propriedade height 233 propriedade paintsDefaultBackground 63, 70 propriedade pdfCapability 272 propriedade placeLoadStringContentInApplication Sandbox 35 propriedade runtimeApplicationDomain 242 propriedade width 233 classe HTMLPDFCapability 272 classe HTMLUncaughtScriptException 253 classe Icon método bounce() 102 propriedade bitmaps 101 método setAsDefaultApplication() 52 método() copy() 152 propriedade activeWindow 72 propriedade applicationDescriptor 298 propriedade autoExit 296 propriedade icon 101 propriedade id 298 propriedade idleThreshold 300 propriedade lastUserInput 300 propriedade publisherID 298, 322 propriedade runtimePatchLevel 300 propriedade runtimeVersion 300 propriedade startAtLogin 294 propriedade supportsDockIcon 101 propriedade supportsMenu 98 propriedade supportsSystemTrayIcon 101 classe NativeBoundsEvent 79 classe NativeDragEvent propriedade clipboard 139 propriedade dropAction 138, 139 classe NativeDragManager método acceptDragDrop() 134, 139 método doDrag() 134, 136, 139 classe NativeMenu 88, 96 classe NativeMenuItem 88 método startMove() 78 método startResize() 77 método() activate 67 propriedade alwaysInFront 73 propriedade stage 70 propriedade systemChrome 62 propriedade systemMaxSize 67 propriedade systemMinSize 67 propriedade transparent 62, 63 propriedade type 62 propriedade visible 67, 73 classe NativeWindowDisplayStateEvent 80 classe NativeWindowInitOptions 66, 67 Classe NetStream método preloadEmbeddedMetadata() 279 classe NetStream método resetDRMVouchers() 282 método setDRMAuthenticationCredentials() 2 78, 282 classe Netstream conteúdo criptografado, reprodução com 278 classe Responder 174, 184 classe Screen 82 método getScreenForRectangle() 83 propriedade data 90 propriedade mainScreen 83 propriedade keyEquivalent 89 propriedade screens 83 propriedade keyEquivalentModifiers 89 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 375 Índice classe Security método allowDomain() 36, 40 códigos de idiomas, seleção para aplicativo 344 propriedade sandboxType 300 colunas (banco de dados) 166 CSS acesso a estilos HTML do ActionScript 246 classe SQLCollationType 167 colunas AUTOINCREMENT (SQL) 185 classe SQLColumnNameStyle 167 colunas INTEGER PRIMARY KEY (SQL) 185 cursor, efeitos de arrastar e soltar 139, 143 comandos, menu D dados binários classe SQLConnection 167 método attach() 186 método open 169 método open() 169 método openAsync() 169, 172 classe SQLError 167, 174 classe SQLErrorEvent 167, 174 Consulte itens de menu compactação de dados 157 compactação deflate 157 compactação ZLIB 157 compilador acompc 245 extensões do AIR para 231 Consulte matrizes de bytes dados criptografados, armazenamento e recuperação 215 declaração de prática de certificação (CPS) 326 classe SQLEvent 167 comprovantes, utilização com conteúdo criptografado por DRM 277 classe SQLIndexSchema 167 conexão com um banco de dados 172 definir a ordem das janelas 73 classe SQLMode 167, 173 classe SQLResult 167, 184 configurações de FlashVars (para usar badge.swf) 314 delimitador de caminho (sistema de arquivos) 110 classe SQLSchemaResult 167 Configurações de Registro do Windows 26 depuração classe SQLStatement 167, 173 Construtores de funções (em JavaScript) 221 método execute 175 conteúdo em PDF default_badge.html 314 uso de ADL 356 desinstalação método execute() 177, 184 adição a aplicativos AIR 272 método getResult() 184 carregamento 273 objeto parameters 174 comunicação JavaScript 273 dimensões, janelas 51 limitações conhecidas 275 diretório Arquivos de Programas (Windows) 312 propriedade parameters 175 propriedade sqlConnection 174 propriedade text 174, 175, 177, 185 classe SQLTableSchema 167 conteúdo SWF diretório da área de trabalho 108 sobreposição em HTML 69 diretório de armazenamento do aplicativo 25, 108, 112, 240 cookies 223 classe SQLTriggerSchema 167 cópia de arquivos 119 classe SQLUpdateEvent 167 cópia de diretórios 117 classe SQLViewSchema 167 copiar e colar atalhos do teclado 151 método addChild() 70 comandos de menu 151 método addChildAt() 70 equivalentes de teclas 153 propriedade displayState 80 HTML 149, 223 propriedade nativeWindow 66, 72 itens de menu padrão (Mac OS) 152 propriedade scaleMode 67, 77 classe StageDisplayState 80 classe StageScaleMode 67, 77 tempo de execução do AIR 2 em HTML 219 classe SQLTransactionLockType 167 classe Stage aplicativos do AIR 26 credenciais para conteúdo criptografado por DRM 286 diretório de documentos 108 diretório do aplicativo 108 diretório inicial 108 diretório My documents (Windows) 108 diretórios 108, 116 cópia 117 criação 116 enumeração 117 exclusão 118, 120 invocação do aplicativo 292 movimentação 117 referência 108 classe StatusEvent 278 credenciais do usuário e segurança 42 classe TextField criação de diretórios 116 diretórios temporários 116 HTML carregado em 233 criptografia 277 distribuição de aplicativos do AIR 312 tags img 28 criptografia AES-CBC de 128 bits 215 Documentação do ActionScript 9 classe Updater 328 criptografia de conteúdo de vídeo 277 Documentação do Adobe 9 Classe URLStream 222 criptografia de dados 215 Documentação do Flash 9 classe Window 59 cromo do sistema 62 documentação, relacionada 9 classe WindowedApplication 59 Classe XMLList 239 janelas HTML 67 cromo personalizado 62 dois pontos (:) caractere, em nomes de parâmetro de instrução SQL 175 Clipboard 223 DPAPI (associação de dados criptografados com usuários) 215 códigos de erro DRM 277 DRM 286 credenciais 286 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 376 Índice E elemento allowBrowserInvocation (arquivo do descritor do aplicativo) 52, 291, 294 elemento content (arquivo do descritor do aplicativo) 50 elementos frame 219, 222, 227 evento load 219, 221, 235, 242 elementos iframe 30, 219, 222, 227 evento locationChange 252 empacotamento de arquivos do AIR evento mouseDown 77, 134 ferramenta para desenvolvedores do AIR (ADT) 358 evento mouseMove 134 evento move 61, 79 elemento customUpdateUI (arquivo de descrição do aplicativo) 291, 330 Endian.BIG_ENDIAN 156 evento moving 79 elemento customUpdateUI (arquivo do descritor do aplicativo) 52 Endian.LITTLE_ENDIAN 156 evento nativeDragComplete 134, 138, 140 entre scripts 35, 241, 248 evento nativeDragDrop 134 elemento description (arquivo do descritor do aplicativo) 49 enumeração de diretórios 117 evento nativeDragEnter 134, 138, 139, 140 enumeração de telas 83 evento nativeDragExit 134, 140 elemento filename (arquivo de descrição do aplicativo) 47 equivalentes de tecla de comandos de menu 89 evento nativeDragOver 134, 138, 139, 140 elemento fileTypes (arquivo do descritor do aplicativo) 52, 299 equivalentes de teclas elemento height (arquivo do descritor do aplicativo) 51 esquema de URL app-storage 25, 39, 42, 112, 273 elemento icon (arquivo do descritor do aplicativo) 51 esquema de URL app-support 248 evento result 174 esquema de URL de aplicativo 39, 42, 68, 112, 220, 240, 248, 273 evento scroll 252 esquema de URL de arquivo 39, 240 evento uncaughtScriptExcpetion 252 esquema de URL do javascript 227 evento userIdle 300 esquema de URL javascript 33, 237 evento userPresent 300 elemento initialWindow (arquivo do descritor do aplicativo) 50 esquema URL de arquivo 112 eventos esquemas de URL 112 classe NativeWindow 79 elemento installFolder (arquivo do descritor do aplicativo) 49 estrutura de atualização 332 HTML 252 evento active 79 janelas nativas 61 elemento maximizable (arquivo do descritor do aplicativo) 51 evento browserInvoke 295, 320 manipuladores 255 elemento maxSize (arquivo do descritor do aplicativo) 51 evento close 79 menu 88, 96 evento closing 74, 79, 255, 296 elemento id (arquivo do descritor do aplicativo) 47 elemento id (classe NativeApplication) 298 elemento initialWindow (arquivo de descrição do aplicativo) 60 copiar e colar 153 evento nativeDragStart 134, 140 evento nativeDragUpdate 134, 140 evento resize 61, 79 evento resizing 79 evento select 88, 97, 98 ouvintes 255 elemento minimizable (arquivo do descritor do aplicativo) 51 Evento complete 242, 252 eventos load 238 evento complete 246 eventos menuItemSelect 89 elemento minSize (arquivo do descritor do aplicativo) 51 evento contextmenu 93 eventos menuSelect 89 evento da área de transferência 224 eventos unload 225 elemento name (arquivo de descrição do aplicativo) 48 evento de copiar 150 exclusão de arquivos 120 exclusão de diretórios 118, 120 elemento programMenuFolder (arquivo do descritor do aplicativo) 50 evento de recortar 150 evento deactivate 79 execução de aplicativos do AIR 312, 320 evento displaying 88, 98 exibições elemento resizable (arquivo do descritor do aplicativo) 51 evento displayStateChange 61, 80 elemento title (arquivo do descritor do aplicativo) 51 evento displayStateChanging 61, 80 elemento transparent (arquivo do descritor do aplicativo) 51 evento drag 141, 224 elemento version (arquivo do descritor do aplicativo) 47 evento dragenter 141, 224 elemento visible (arquivo do descritor do aplicativo) 51 evento dragover 141, 224 evento dominitialize 228 evento dragend 141, 224 evento dragleave 141, 224 Consulte telas extensões (arquivo), associação com um aplicativo AIR 299 extensões (arquivo), associação com um aplicativo do AIR 52, 293 F FDB (depurador) 356 fechamento de janelas 61, 74, 296 elemento width (arquivo do descritor do aplicativo) 51 evento dragstart 141, 224 elemento x (arquivo do descritor do aplicativo) 51 evento enterFrame 70 evento error 174 elemento y (arquivo do descritor do aplicativo) 51 arquivos AIRI 366 evento htmlBoundsChanged 252 criação de certificados auto-assinados 368 evento drop 141, 224 evento htmlDOMInitialize 252 fechar aplicativos 296 ferramenta para desenvolvedores do AIR (ADT) DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 377 Índice empacotamento de um arquivo do AIR 358 I ícones itens de menu 88 ativados 90 opções de assinatura 363 animação 101 caracteres mnemônicos 90 Flash Player 54, 217, 220, 239 aplicativo 51 copiar e colar 152 Flex bandeja do sistema 101 criação 92 barra de tarefas 73, 101 dados, atribuição a 90 encaixe 101, 102 estados 90 imagens 101 marcados 90 remoção 101 seleção 97 suporte a arrastar e soltar 135 FMRMS (Servidor de gerenciamento de direitos do Flash Media) 277 formato de arquivo ZIP 159 formato GZIP 157 função AC_FL_RunContent() (em default_badge.html) 314 ícones de bandeja do sistema 87, 90 ícones de encaixe 102 teclas de aceleração 89 itens de menu ativados 90 função eval() 28, 32, 221, 234, 235 menus 90 itens de menu marcados 90 função setInterval() 33, 226, 237 minimização de janelas e 73 itens de menus função setTimeout() 33, 226, 237 funções (JavaScript) construtor 237 definições 33 literais 33 ícones de proxy ícones do encaixe suporte 101 ícones na bandeja do sistema suporte 101 G geração de código dinâmico 32 gerenciamento de direitos digitais 277 gesto de arrastar para dentro 133, 138 equivalentes de tecla 89 Mac OS 65 J janela ativa 72, 73 janelas 59 aparência 62 ícones na barra de tarefas 73, 101 ativação 67 ícones na barra de título (Windows) 65 ativas 72, 73 ícones no encaixe classes para trabalhar com 60 pular 102 comportamento 62 gesto de arrastar para fora 133, 135 identificadores de editor 298 criação 65, 71, 233 gravação de arquivos 121 identificadores do editor 322 cromo 62 idiomas, com suporte no instalador do aplicativo do AIR 49 cromo do sistema 62 IDs digitais de assinatura Sun Java 323 estilo 62 IDs digitais Microsoft Authenticode 323 eventos 79 IDs do aplicativo 47 fechamento 61, 74, 296 imagens de bitmap, definição para ícones 101 fluxo de eventos 61 H HMTL copiar e colar 149 suporte a arrastar e soltar 133, 142 HTML caixas de proteção 220 impressão 220 carregamento de conteúdo 233 informações de copyright para aplicativos do AIR 49 DOM, acesso do ActionScript 242 eventos 252 extensões do AIR para 227 impressão 220 janelas 67 objetos incorporados 219 plug-ins 219 rolagem 252 segurança 30, 219, 248 sobreposição de conteúdo SWF 69 HTMLLoader propriedade placeLoadStringContentInApplication Sandbox 233 cromo personalizado 62 gerenciamento 72 iniciais 60 inicialização 65 inicialização (sistema), inicialização de um aplicativo do AIR na 294 janelas de utilitário 62 inicialização automática (inicialização de um aplicativo do AIR no login) 294 leves 62 inicializar aplicativos do AIR 291 minimização 51, 61, 73, 75 instalação de aplicativos do AIR 312 modos de dimensionamento de palco 67 Instrução CREATE TABLE (SQL) 170 mostrar 73 Instrução DELETE (SQL) 185 movimentação 61, 77, 78 Instrução INSERT (SQL) 189 movimento 83 Instrução SELECT (SQL) 177, 189 não retangulares 63 Instrução UPDATE (SQL) 185 ocultar 73 instruções, SQL 173 ordem 73 interface de usuário de atualização personalizada 330 ordem de exibição 73 invocação de aplicativos do AIR 291 invocar evento 291 janelas normais 62 maximização 51, 61, 75 plano de fundo de 63 posição 51 propriedades 50 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 378 Índice redimensionamento 51, 61, 77 restauração 61, 75 tamanho 67 tamanho de 51 tamanho máximo 67 tamanho mínimo 67 tipos 62 transparência 51, 63 visibilidade 51 janelas da área de trabalho Consulte janelas janelas de utilitário 62 janelas em tela cheia 80 Janelas HTML DOM e nativas 60 janelas leves 62 janelas nativas Consulte janelas janelas normais 62 janelas pop-up 73 janelas transparentes 51, 63 JavaScript acesso às APIs do AIR 239 arquivo AIRAliases.js 218, 239 como evitar erros de segurança 235 entre scripts ActionScript 241 erros 235, 242, 253, 256 eventos de erro 252 eventos, tratamento 255 PDF 273 programação 233 segurança 248 suporte do AIR para 220 tempo de execução do AIR e 217 JCA (arquitetura de criptografia Java) 363 JSON 221 L leitura de arquivos 121 ligação forte de dados criptografados 215 limpeza de diretórios 118 linhas (banco de dados) 166, 184 linhas separadoras, menu 92 lista de revogação de certificado (CRL) 326 listas de arquivos suporte a arrastar e soltar 142 literais de objeto (em JavaScript) 32 Livros da Adobe Press 9 lixeira (exclusão de arquivo) 120 localização 343 login do sistema, inicialização de um aplicativo do AIR no 294 menus de janela 86, 98 login, inicialização de um aplicativo do AIR no 294 menus nativos M Mac OS barra de ferramentas 65 ícones de proxy 65 criação 90 Consulte menus menus pop-up 86, 96 criação 90 método acceptDragDrop() (classe NativeDragManager) 134, 139 manipulador onclick 238 método activate() (classe NativeWindow) 67, 73 manipulador onload 32 método addChild() (classe Stage) 70 manipulador onmouseover 238 método addChildAt() (classe Stage) 70 matrizes de bytes ordem de bytes 156 método attach() (classe SQLConnection) 186 position em 155 método bounce() (classe Icon) 102 tamanho de 155 método browseForDirectory() (classe File) 110 maximização de janelas 51, 61, 75 menu aplicativo 98 estrutura 88 eventos 98 menu Iniciar (Windows) 50 menus 86 aplicativo 90 classes de trabalho 87 comandos de copiar e colar 151 método browseForOpen() (classe File) 111 método browseForSave() (classe File) 111 método clearData() objeto ClipboardData 223 objeto DataTransfer 142, 224 método close() classe NativeWindow 74 método close() (objeto Window) 60 método compress() (classe ByteArray) 157 criação 90 método copy() (classe NativeApplication) 152 encaixe 87 método copyTo() (classe File) 119 equivalentes de tecla 89 método copyToAsync() (classe File) 119 estrutura 87 método createDirectory() (classe File) 116 fluxo de evento 88, 96 método createElement() (objeto Document) 238 ícone de bandeja do sistema 90 ícones de bandeja do sistema 87 item de encaixe 90 itens 88 janela 90, 98 linhas separadoras 92 menus de contexto 92 método createRootWindow() (classe HTMLLoader) 67, 69, 233 método createTempDirectory() (classe File) 116, 121 método createTempFile() (classe File) 121 método deleteDirectory() (classe File) 118 personalizados 87 método deleteDirectoryAsync() (classe File) 118 pop-up 90, 96 método deleteFile() (classe File) 120 sistema padrão 87 método deleteFileAsync() (classe File) 120 submenus 88, 91 tipos de 87 método dispatchEvent() (classe NativeWindow) 61 XML, definição com 94 método display() (classe NativeMenu) 96 menus de aplicativo 86, 98 criação 90 menus de contexto 86, 92 HTML 93 menus de encaixe 87 Método Document object wirtelin() 225 método doDrag() (classe NativeDragManager) 134, 136, 139 método execute() (classe SQLStatement) 175, 177, 184 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 379 Índice método openAsync() (classe SQLConnection) 169, 172 método writeln() (objeto Document) 225, 238 método getApplicationVersion() (arquivo air.swf) 318 método orderBehind() (classe NativeWindow) 73 método writeObject() (classe ByteArray) 154 método getData() método orderInBackOf() (classe NativeWindow) 73 método writeUTFBytes() (classe ByteArray) 154 método orderInFrontOf() (classe NativeWindow) 73 Microsoft Windows método orderToBack() (classe NativeWindow) 73 migração de uma assinatura 325, 367 método orderToFront() (classe NativeWindow) 73 monitores método exit() classe NativeApplication 296 classe Clipboard 139 evento de copiar e colar HTML 150 objeto ClipboardData 223 objeto DataTransfer 145, 224 método getData() (classe Clipboard) 135 método getData() (de uma propriedade dataTransfer de um evento de arrastar HTML) 142 método getDefaultApplication() (classe NativeApplication) 299 método postMessage() (objeto PDF) 274 ícones na barra de título 65 minimização de janelas 51, 61, 73, 75 Consulte telas método preloadEmbeddedMetadata() (classe NetStream) 279 mostrar janelas 73 movimentação de arquivos 119 método print() (objeto Window) 220 movimentação de diretórios 117 método getDirectoryListing() (classe File) 117 método readBytes() (classe ByteArray) 154 movimentação de janelas 61, 77, 78 método getDirectoryListingAsync() (classe File) 117 método readInt() (classe ByteArray) 154 método getResult() (classe SQLStatement) 184 método getScreensForRectangle() (classe Screen) 83 método getStatus() (arquivo air.swf) 317 método hasEventListener() 257 método installApplication() (arquivo air.swf) 319 método readFloat() (classe ByteArray) 154 método readObject() (classe ByteArray) 154 método readUTFBytes() (classe ByteArray) 154 método relativize() (classe File) 113 método removeAsDefaultApplication() (classe NativeApplication) 299 método removeEventListener() 256 método resetDRMVouchers() (classe NetStream) 282 N namespace XML (arquivo do descritor do aplicativo) 45 navegação para selecionar um arquivo 111 para selecionar um diretório 110 navegadores da Web detecção de tempo de execução do AIR de 317 método resolvePath() (classe File) 108 detecção se um aplicativo do AIR está instalado de 318 método listRootDirectories() (classe File) 108 método restore() (classe NativeWindow) 75 inicialização de aplicativos do AIR de 320 método load() (classe FileReference) 129 método loadBytes() (classe Loader) 41 método setAsDefaultApplication() (classe NativeApplication) 52, 299 método Loader.loadBytes() 41 método setData() método isSetAsDefaultApplication() (classe NativeApplication) 299 método loadString() (classe HTMLLoader) 35, 233 método maximize() (classe NativeWindow) 75 método minimize() (classe NativeWindow) 75 método moveTo() classe File 119 objeto Window 60 método moveToAsync() (classe File) 119 método save() (classe FileReference) 129 objeto ClipboadData 223 objeto DataTransfer 142, 144, 224 instalação de aplicativos do AIR de 319 navegadores da web inicialização de um aplicativo do AIR de 294 níveis de patch tempo de execução do AIR 300 método setDragImage() (de uma propriedade dataTransfer de um evento de arrastar HTML) 142 níveis de patch, tempo de execução do AIR 45 método setDRMAuthenticationCredentials() (classe NetStream) 278, 282 nome de coluna ROWID (SQL) 185 método startMove() (classe NativeWindow) 78 nome do editor 321 nome de coluna OID (SQL) 185 nome de coluna _ROWID_ (SQL) 185 nome do editor desconhecido (no instalador do aplicativo do AIR) 321 método moveToTrash() (classe File) 120 método startResize() (classe NativeWindow) 77 método moveToTrashAsync() (classe File) 120 método uncompress() (classe ByteArray) 157 método NativeApplication.setAsDefaultApplic ation() 299 método update() (classe Updater) 328 método open() método writeBytes() (classe ByteArray) 154 O objeto Canvas 222, 229 classe SQLConnection 169 método writeFloat() (classe ByteArray) 154 objeto DataTransfer objeto Window 35, 67, 227 método writeInt() (classe ByteArray) 154 método open() (classe SQLConnection) 169 método write() (objeto Document) 225, 238 nomes de usuário configuração para conteúdo de mídia criptografado 277 propriedade types 145 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 380 Índice objeto DataTransfer (HTML arrastar e soltar) 142, 143, 144, 145, 224 objeto Document método write() 33, 225, 238 plug-ins (em HTML) 219 propriedade creator (classe File) 118 pontes de caixa de proteção 31, 35, 219, 220, 235, 248 propriedade CSS -webkit-user-drag 144 propriedade currentDirectory (classe InvokeEvent) 292 método writeln() 33, 238 ponto de interrogação (?) caractere, em parâmetros SQL sem nome 176 propriedade designMode 145, 225 posição de janelas 51 propriedade currentDomain (classe ApplicationDomain) 242 propriedade stylesheets 246 posição do mouse ao arrastar 140 propriedade data privilégios necessários para atualizar o tempo de execução do AIR ou de um aplicativo do AIR 23 propriedade de argumentos objeto Document object método createElement() 238 objeto Window método moveTo() 60 privilégios necessários para atualizar o tempo de execução do AIR ou um aplicativo do AIR 313, 319 método open 227 programação assíncrona método close() 60 método open() 35, 67 bancos de dados 168, 172, 190 método print() 220 sistema-arquivo 106 objeto htmlLoader 218 XMLHttpRequests 238 objeto nativeWindow 218 programação síncrona propriedade childSandboxBridge 31 bancos de dados 168, 172, 190 propriedade htmlLoader 68, 226, 233 sistema-arquivo 106 propriedade nativeWindow 60, 68, 226 propriedade opener 68 propriedade parent 68 propriedade parentSandboxBridge 31, 226, 249 propriedade runtime 28, 34, 68, 218, 226, 239 XMLHttpRequests 238 propriedade activeWindow (classe NativeApplication) 72 propriedade air (arquivo AIRAliases.js) 218, 239 propriedade allowLoadBytesCodeExecution (classe LoaderContext) 41 objeto XMLHttpRequest 34, 221, 227, 238 propriedade alwaysInFront (classe NativeWindow) 73 objetos Date, conversão entre ActionScript e JavaScript 246 propriedade applicationDescriptor (classe NativeApplication) 298 objetos incorporados (em HTML) 219 propriedade applicationStorageDirectory (classe File) 108 objetos RegExp, conversão entre ActionScript e JavaScript 246 objetos serializados 135 propriedade autoExit classe NativeApplication 296 classe NativeMenuItem 90 classe BrowserInvokeEvent 295 classe InvokeEvent 292 propriedade de tipos evento de arrastar HTML 142 propriedade designMode (objeto Document) 145, 225 propriedade desktopDirectory (classe File) 108 propriedade displayState (classe Stage) 80 propriedade documentsDirectory (classe File) 108 propriedade dropAction (classe NativeDragEvent) 138, 139 propriedade dropEffect (objeto DataTransfer) 142, 143, 224 propriedade effectAllowed (objeto DataTransfer) 142, 143, 144, 224 propriedade encoding (classe File) 115 propriedade exists (classe File) 118 propriedade height (classe HTMLLoader) 233 propriedade hostContainer (PDF) 274 propriedade htmlLoader (objeto Window) 68, 218, 226, 233 propriedade icon (classe NativeApplication) 101 suporte a arrastar e soltar 133 propriedade bitmaps (classe Icon) 101 suporte a copiar e colar 149 ocultar janelas 73 propriedade bytesAvailable (classe ByteArray) 155 propriedade innerHTML 33, 225, 238 ordem das janelas 73 propriedade childSandboxBridge propriedade isDirectory (classe File) 118 ordem de bytes 156 classe LoaderInfo 36 ordem de bytes de big-endian 156 objeto Window 31 ordem de bytes de little-endian 156 ordem de exibição, janelas 73 P parâmetros nomeados (em instruções SQL) 175 parâmetros sem nome (em instruções SQL) 176 parâmetros, em instruções SQL 175 PDF suporte para 219, 272 plano de fundo de janelas 63 propriedade idleThreshold (classe NativeApplication) 300 propriedade isHTTPS (classe BrowserInvokeEvent) 295 propriedade clientX (eventos de arrastar HTML) 142 propriedade keyEquivalent (classe NativeMenuItem) 89 propriedade clientY (eventos de arrastar HTML) 142 propriedade keyEquivalentModifiers (classe NativeMenuItem) 89 propriedade clipboard (classe NativeDragEvent) 139 propriedade label (classe NativeMenuItem) 152 propriedade clipboardData (eventos da área de transferência) 224 propriedade lastInsertRowID (classe SQLResult) 184 propriedade clipboardData (eventos de copiar e colar HTML) 150 propriedade lastUserInput (classe NativeApplication) 300 propriedade contextMenuOwner (classe ContextMenuEvent) 92 propriedade length (classe ByteArray) 155 propriedade creationDate (classe File) 118 propriedade mainScreen (classe Screen) 83 propriedade lineEnding (classe File) 115 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 381 Índice propriedade messageHandler (PDF) 274 propriedade mnemonicIndex classe NativeMenuItem 90 propriedade modificationDate (classe File) 118 propriedade mouseTarget (classe ContextMenuEvent) 92 propriedade screenX (eventos de arrastar HTML) 142 propriedade screenY (eventos de arrastar HTML) 142 propriedade securityDomain (classe BrowserInvokeEvent) 295 propriedade separator (classe File) 115 propriedade name (classe File) 118 propriedade size (classe File) 118 propriedade nativePath (classe File) 108, 118 propriedade spaceAvailable (classe File) 115 propriedade nativeWindow propriedade sqlConnection (classe SQLStatement) 174 classe Stage 66, 72 objeto Window 218, 226 propriedade nativeWindow (objeto Window) 60, 68 propriedade opener (objeto Window) 68 propriedade paintsDefaultBackground (classe HTMLLoader) 63, 70 propriedade parameters (classe SQLStatement) 174, 175 propriedade parent (classe File) 118 propriedade parent (objeto Window) 68 propriedade parentSandboxBridge classe LoaderInfo 36 objeto Window 31, 226 Q quadros 30 R recurso de invocação do navegador 52, 294 Recursos propriedade de idioma 344 propriedade de idiomas 344 redimensionamento de janelas 51, 61, 77 referências a objetos suporte a arrastar e soltar para 133 propriedade stage classe NativeWindow 70 propriedade startAtLogin (classe NativeApplication) 294 referências de objetos suporte a copiar e colar 149 registro de tipos de arquivo 299 propriedade styleSheets (objeto Document) 246 requisitos propriedade subErrorID (classe DRMErrorEvent) 286 restauração de janelas 61, 75 processamento em PDF 272 propriedade submenu classe NativeMenuItem 88 propriedade supportsDockIcon (classe NativeApplication) 101 propriedade supportsMenu (classe NativeApplication) 98 S sair de aplicativos do AIR 291 sair do evento 296 screens 82 security propriedade parentSandboxBridge (objeto Window) 249 propriedade supportsSystemTrayIcon (classe NativeApplication) 101 propriedade pdfCapability (classe HTMLLoader) 272 propriedade systemChrome (classe NativeWindow) 62 ataques de downgrade 42 propriedade placeLoadStringContentInApplication Sandbox (classe HTMLLoader) 35, 233 propriedade systemMaxSize (classe NativeWindow) 67 cache entre domínios 29 XMLHTTPRequest 228 segurança banco de dados 176 propriedade systemMinSize (classe NativeWindow) 67 caixa de proteção do aplicativo 27 caixas de proteção de não-aplicativos 29 propriedade position (classe ByteArray) 155 propriedade text (classe SQLStatement) 174, 175, 177, 185 propriedade publisherID (classe NativeApplication) 298, 322 propriedade transparent (classe NativeWindow) 62, 63 carregar conteúdo 68 propriedade runtime (objeto Window) 68, 218, 226, 239 propriedade type (classe File) 118 propriedade runtimeApplicationDomain (classe HTMLLoader) 242 propriedade types propriedade playerType classe Capabilities 300 propriedade runtimePatchLevel (classe NativeApplication) 300 propriedade runtimeVersion (classe NativeApplication) 300 propriedade sandboxRoot frame 30 iframe 30 propriedade sandboxType classe BrowserInvokeEvent 295 classe Security 300 propriedade scaleMode classe Stage 77 propriedade screens (classe Screen) 83 propriedade type (classe NativeWindow) 62 caixas de proteção 27, 219, 220, 248, 300 campos de texto 28 credenciais do usuário 42 criptografia de dados 215 CSS 29 evento de copiar e colar HTML 150 diretório de armazenamento do aplicativo 25 objeto DataTransfer 224 entre scripts 35 propriedade types (objeto DataTransfer) 145 propriedade url classe File 108, 118 propriedade url (classe File) 108 propriedade userDirectory (classe File) 108 propriedade visible classe NativeWindow 67, 73 propriedade width (classe HTMLLoader) 233 propriedades outerHTML 225 protocolo asfunction 29 erros JavaScript 235 estruturas Ajax 33 frames 29, 30 função eval() 32 geração de código dinâmico 32 HTML 30, 32, 217, 219, 234 iframes 29, 30 instalação (aplicativo e tempo de execução) 23 JavaScript 248 método Loader.loadBytes() 41 DESENVOLVIMENTO DE APLICATIVOS DO ADOBE AIR 1.5 COM O FLASH CS4 PROFESSIONAL 382 Índice objetos XMLHttpRequest 34 pontes de caixa de proteção 31, 35, 248 práticas recomendadas 41 privilégios de instalação do usuário 23 protocolo asfunction 29 T tabelas (banco de dados) 166 criação 170 tags de script 221, 225, 238, 240, 244 propriedade src de 33 sistema de arquivos 39 tags img (no conteúdo do objeto TextField) 28 tags img 28 tamanho de janelas 51 window.open() 35 tamanho, janelas 67 recurso de invocação do navegador 295 V validação de dados, invocação do aplicativo 295 versões, aplicativo AIR 300 vídeos FLV, criptografia de 277 visibilidade de janelas 51 volumes de raiz 108 W WebKit 217, 220, 231 segurança de cache entre domínios 29 Tecla Command 89 Segurança de JavaScript 32 Tecla Control 89 segurança e ataques de downgrade 42 tecla Shift 89 -webkit-border-horizontal-spacing CSS property 231 senhas teclas de aceleração de comandos de menu 89 -webkit-border-vertical-spacing CSS property 231 teclas do modificador, itens de menu 89 -webkit-line-break CSS property 231 Servidor de gerenciamento de direitos do Flash Media 277 teclas primárias -webkit-margin-bottom-collapse CSS property 231 sistema de arquivos tela principal 83 configuração para conteúdo de mídia criptografado 277 segurança 39 itens de menu 89 telas -webkit-margin-collapse CSS property 231 -webkit-margin-start CSS property 231 Site de suporte da Adobe 9 enumeração 83 -webkit-margin-top-collapse CSS property 231 SQL janelas, movimento entre 83 -webkit-nbsp-mode CSS property 231 principal 83 -webkit-padding-start CSS property 231 classes usadas com 167 colunas AUTOINCREMENT 185 tempo de execução do AIR -webkit-rtl-ordering CSS property 231 colunas INTEGER PRIMARY KEY 185 atualização 23 -webkit-text-fill-color CSS property 232 digitação de dados 176, 189 desinstalação 2 -webkit-text-security CSS property 232 instrução CREATE TABLE 170 detecção 300, 317 propriedade -webkit-user-drag CSS 232 instrução DELETE 185 níveis de patch 45, 300 propriedade CSS -webkit-user-drag 141 instrução INSERT 189 nova funcionalidade 54 -webkit-user-modify CSS property 232 instrução SELECT 177, 189 tempo ocioso (usuário) 300 propriedade -webkit-user-select CSS 232 instrução UPDATE 185 texto propriedade CSS -webkit-user-select 141, 144 instruções 173 nome de coluna OID 185 suporte a arrastar e soltar 133, 142 suporte a copiar e colar 149 nome de coluna ROWID 185 tipos de dados, banco de dados 189 nome de coluna _ROWID_ 185 tipos MIME parâmetros em instruções 175 arrastar e soltar HTML 142 parâmetros nomeados (em instruções) 175 copiar e colar HTML 223 parâmetros sem nome (em instruções) 176 sobre 167 stylesheets, HTML manipulação no ActionScript 246 tradução de aplicativos 343 U UntrustedAppInstallDisabled (configurações de Registro do Windows) 26 Suporte para bancos de dados SQLLite 164 UpdateDisabled (configurações de Registro do Windows) 26 suporte para bancos de dados SQLLite URLs 240 submenus 88, 91 Consulte também bancos de dados carregamento de conteúdo HTML de 233 suporte técnico 9 suporte a arrastar e soltar 133, 142 SVG (gráficos vetoriais escaláveis) 220 suporte a copiar e colar 149 X XML classe 239 definição de menus usando 94 xmlns (arquivo do descritor do aplicativo) 45