Para todos que, apesar de tudo, conseguiram fazer a escolha certa.
Esta é uma tradução de uma série de artigos de Mark Murphy, do CommonsWare, amplamente conhecido no stackoverflow, além do autor dos livros “O Guia do Codificador Ocupado para o Desenvolvimento Android”, “Componentes da Arquitetura do Android”. Alguns termos não são traduzidos especificamente.
Armazenamento interno
Há muita confusão em relação ao modelo de armazenamento Android. A confusão aumentou significativamente com as alterações no Android 4.4 no modelo de armazenamento e, desde então, a situação não melhorou. Existem inúmeras perguntas sobre o Stack Overflow e recursos semelhantes, onde as pessoas claramente não são completamente versadas nos vários modelos de armazenamento Android.
O que os usuários consideram Armazenamento interno
Dependendo do modelo do seu dispositivo, os usuários acabarão acessando Configurações -> Armazenamento no dispositivo ou em um local equivalente e poderão ver uma tela que descreve "Armazenamento interno" .
O usuário acha que toda a unidade flash embutida é "Armazenamento Interno". Felizmente, o Google começou a mudar esse termo com o Android 8.0, passando para "armazenamento geral" em vez de "armazenamento interno".
No entanto, os usuários ainda podem ver o “armazenamento interno” em locais como a janela do Windows Explorer quando o dispositivo está conectado via USB.
O que o Google considera armazenamento interno
Infelizmente, o que os usuários veem não é o mesmo que o SDK do Android considera "armazenamento interno", o que leva a alguma confusão. Se você ler a documentação do Android no repositório interno , esta descrição será pelo menos vaga (o texto do comentário mudou desde que este artigo foi escrito):
Você pode salvar arquivos diretamente na memória interna do dispositivo. Por padrão, os arquivos armazenados no armazenamento interno são privados para seu aplicativo e outros aplicativos não podem acessá-los (assim como o usuário). Quando o usuário desinstala o aplicativo, esses arquivos são excluídos.
Na verdade, o SDK do Android define "armazenamento interno" como um diretório especial exclusivo para seu aplicativo, onde ele pode hospedar arquivos. Conforme sugerido na documentação, esses arquivos destinam-se à leitura e gravação por padrão para o seu aplicativo e são proibidos para qualquer outro aplicativo (exceção: os usuários que trabalham com gerenciadores de arquivos com privilégios de superusuário em dispositivos raiz podem acessar tudo).
O contexto possui alguns métodos básicos que permitem acessar o armazenamento interno, incluindo:
getCacheDir()
getDir()
getDatabasePath()
getFilesDir()
openFileInput()
openFileOutput()
Outros métodos contarão com eles, como openOrCreateDatabase()
. Outras classes também contarão com elas, como SQLiteOpenHelper
e SQLiteOpenHelper
.
Onde o armazenamento interno é armazenado ... Às vezes
Se você observar várias postagens de blog, respostas do StackOverflow e livros lançados em 2012 ou em versões anteriores, você será informado de que o “armazenamento interno” do seu aplicativo está localizado em /data/data/your.application.package.name
.
Dentro, haverá alguns diretórios criados automaticamente pelo Android, à medida que você usa alguns dos métodos Context. Por exemplo, getFilesDir()
retorna um objeto File
apontando para o diretório files/
no armazenamento interno do seu aplicativo.
Onde está armazenado o armazenamento interno ... O resto do tempo
No entanto, o armazenamento interno do seu aplicativo nem sempre está no local especificado. Para os desenvolvedores, há uma regra que você deve aprender com esta série de postagens no blog:
NUNCA CAMINHOS DE CÓDIGO .
De tempos em tempos, vejo desenvolvedores fazendo algo parecido com isto:
File f=new File("/data/data/their.app.package.name/files/foo.txt");
Isso não é crime, é pior, isso é um erro.
O movimento certo e escreva menos:
File f=new File(getFilesDir(), "foo.txt");
Mais importante, o armazenamento interno nem sempre está no mesmo lugar . Vale ressaltar que temos o conceito de perfis de usuário separados (perfis de usuário separados), começando com o Android 4.2 para tablets e o Android 5.0 para telefones. Cada usuário obtém seu próprio "armazenamento interno". Embora o diretório acima ainda seja usado para o usuário principal, não há garantia de que será usado para contas secundárias.
Explorando o armazenamento interno
A ferramenta Device File Explorer no Android Studio 3.0+ pode exibir todo o armazenamento interno no emulador, bem como o armazenamento interno de aplicativos depurados nos dispositivos de produção.
Na linha de comando, você pode usar adb
com a opção run-as
.
Por exemplo, para fazer upload de um banco de dados do armazenamento interno do usuário primário para sua máquina de desenvolvimento, você pode usar:
adb shell 'run-as your.application.package.name cp /data/data/your.application.package.name/databases/dbname.db /sdcard'
Observe que:
- Você precisará alterar o destino para onde o armazenamento externo está montado no seu dispositivo (mostrado aqui como
/sdcard/
, que não será o mesmo em todos os dispositivos) - Pode ser necessário usar
cat
vez de cp
em dispositivos mais antigos - Depois que o arquivo estiver localizado no armazenamento externo, você poderá usar o
adb pull
para fazer o download para o seu computador ou acessá-lo de outras formas usuais (por exemplo, montando o dispositivo como um disco).
Limitações de armazenamento interno
Em dispositivos Android 1.xe 2.x mais antigos, o armazenamento interno era geralmente localizado em uma seção dedicada do sistema de arquivos, e essa seção era geralmente bastante pequena. O HTC Dream (também conhecido como T-Mobile G1), o dispositivo Android original, tinha uma enorme memória interna de 70 MB para uso de todos os aplicativos (isso não é um erro de digitação, na época medimos a memória em megabytes).
Quando 2.3 dispositivos foram lançados, o armazenamento interno poderia ter 1 GB de tamanho.
O Android 3.0 mudou o modelo de armazenamento, à medida que o armazenamento interno se tornou mais volume. Para dispositivos que anunciam com 4 GB, 8 GB, 16 GB, etc. espaço de armazenamento, geralmente havia tudo isso (menos o conteúdo existente) disponível para armazenamento interno. Veremos o que mudou no Android 3.0 e seu impacto no modelo de armazenamento nas próximas postagens sobre armazenamento externo.
Para o Android 1.xe 2.x, o armazenamento interno era válido apenas para arquivos pequenos, e você precisava usar o armazenamento externo para todo o resto. O Android 3.0 ou superior significa que, para a maioria dos dispositivos e usuários, o armazenamento interno é excelente para arquivos que não são destinados ao uso normal por outros aplicativos ou que são acessíveis ao usuário, independentemente do seu aplicativo. No entanto, alguns usuários experientes acham que mesmo um flash on-board não é suficiente para o que eles querem armazenar, então eles mudam para o armazenamento removível ... que é uma lata de worms (observe λμινς) - uma fonte de muitos problemas imprevisíveis e complexos.
Perguntas frequentes sobre armazenamento interno
Devo criar arquivos no armazenamento interno Legível pelo Mundo ou Gravável pelo Mundo?
Oh, Deuses, não. Use o FileProvider
e sirva esse conteúdo com a implementação do ContentProvider
. Depois disso, você terá pelo menos a oportunidade de usar o sistema de permissão do Android para controlar o acesso a esses arquivos, diferentemente da sua versão, quando qualquer aplicativo no sistema puder estragar esses arquivos.
Bem, e o android:sharedUserId
?
Eu não aconselho.
android: sharedUserId
é um atributo que você pode colocar em um manifesto que indica o identificador lógico do usuário que será usado para seu aplicativo. Qualquer outro aplicativo instalado que assine com a mesma chave de assinatura e solicite o mesmo android:sharedUserId
utilizará o mesmo usuário do Linux do ponto de vista da segurança. O efeito é que esses dois aplicativos podem funcionar impunemente com os arquivos um do outro, pois esses arquivos pertencem ao mesmo usuário do Linux.
Este atributo é realmente destinado a aplicativos pré-instalados, como suíte de software pré-carregado pelo fabricante do dispositivo, operadora de celular ou desenvolvedor de um firmware ROM modificado. Em particular, assim que você instala o aplicativo uma vez, não é possível alterar o valor do seu android:sharedUserId
sem android:sharedUserId
sem bloquear o acesso do usuário a arquivos existentes ... já que o Android não altera os direitos do proprietário dos arquivos existentes ao alterar a conta de usuário do Linux, que executa o aplicativo.
Existem vários riscos quando vários processos acessam arquivos. Alguns subsistemas, como o SQLite, possuem lógica interna para resolver esse problema. Mas se você mesmo organizar seu próprio acesso ao arquivo (por exemplo, através de E / S de File
e Java), precisará fazer algo com acesso simultâneo, e isso é difícil.
Você também precisa lidar com uma situação em que um aplicativo está sendo desinstalado, excluindo arquivos que outro aplicativo usou. Em um modelo de hub e spoke, por exemplo, com um aplicativo e um conjunto de plugins, talvez isso não seja tão arriscado. Em outros modelos, onde os aplicativos são mais justos, você não pode perder os dados do seu aplicativo apenas porque o usuário decidiu excluir algum aplicativo separado.
Finalmente, você não sabe o que o futuro pode trazer. No momento, você pode visualizar seu conjunto de aplicativos como um conjunto fortemente acoplado. Alguém que compra esses aplicativos ou adquire sua empresa pode querer seguir o outro caminho. O uso de recursos de compartilhamento de dados que são ContentProvider
, como o ContentProvider
, oferece mais flexibilidade. Em um mundo ideal, seu aplicativo deve tratar outros aplicativos como um recurso razoavelmente confiável, mas nem sempre acessível, assim como seu próprio serviço da web.
Como impedir que usuários de dispositivos raiz acessem meus arquivos no armazenamento interno?
Só não coloque arquivos no armazenamento interno. Os usuários de dispositivos raiz podem acessar o que precisam no dispositivo, portanto, a única maneira de impedir que eles acessem seus dados é não tê-los no dispositivo.
Alguns desenvolvedores tentarão criptografar seus arquivos com uma senha codificada para que os usuários de dispositivos raiz não possam usar esses arquivos. Isso criará o efeito de um aumento de velocidade por um curto período de tempo. Tudo o que é necessário é uma pessoa interessada em fazer a engenharia reversa do seu aplicativo, que determinou como descriptografar esses arquivos e, em seguida, escreveu uma mensagem em um blog ou fórum sobre como fazer isso.
Em geral, relativamente poucas pessoas com dispositivos enraizadas - eu as classifico em menos de 1%. IMHO, você terá mais sucesso concentrando seu trabalho de engenharia na criação de um aplicativo melhor, em vez de gastar tempo protegendo contra dispositivos raiz.