Compatibilidade com emojis

O objetivo da Biblioteca de Suporte EmojiCompat é manter os dispositivos Android atualizados com os emojis mais recentes. Ela evita que seu app mostre caracteres ausentes de emojis na forma de ☐, que indica que seu dispositivo não tem uma fonte para exibir o texto. Ao usar a Biblioteca de Suporte EmojiCompat, os usuários do seu app não precisam esperar por atualizações do SO do Android para ter os emojis mais recentes.

Dispositivos mostrando emojis
Figura 1. Comparação de emojis.

Confira os seguintes recursos relacionados:

  • Amostra do app Emoji Compatibility (em inglês) app Java | Kotlin

Como a EmojiCompat funciona?

A Biblioteca de Suporte EmojiCompat oferece classes para implementar a compatibilidade com emojis em versões anteriores nos dispositivos com o Android 4.4 (API nível 19) e versões mais recentes. Você pode configurar EmojiCompat com fontes agrupadas ou disponíveis para download. Para mais informações sobre a configuração, consulte as seguintes seções:

A EmojiCompat identifica um emoji para uma CharSequence específica, o substitui por um EmojiSpans se necessário e por fim, renderiza os glifos do emoji. A Figura 2 demonstra o processo.

Processo da EmojiCompat
Figura 2. Processo da EmojiCompat.

Configuração de fontes disponíveis para download

Essa configuração usa o recurso "Fontes para download" da Biblioteca de Suporte para salvar uma fonte de emojis. Ela também atualiza os metadados de emoji necessários que a Biblioteca de Suporte EmojiCompat precisa para acompanhar as versões mais recentes da especificação Unicode.

Adicionar dependência da Biblioteca de Suporte

Para usar a Biblioteca de Suporte EmojiCompat, é necessário modificar as dependências do caminho de classe do seu projeto do app no ambiente de desenvolvimento.

Para adicionar uma Biblioteca de Suporte ao projeto do app:

  1. Abra o arquivo build.gradle do aplicativo.
  2. Adicione a Biblioteca de Suporte à seção dependencies.

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji:emoji:28.0.0")
}

Inicializar a configuração de fonte disponível para download

É necessário inicializar EmojiCompat para carregar os metadados e a face de tipos. Como a inicialização pode demorar um pouco, o processo ocorre em uma linha de execução em segundo plano.

Para inicializar EmojiCompat com a configuração de fonte disponível para download, siga estas etapas:

  1. Crie uma instância da classe FontRequest e forneça a autoridade do provedor de fonte, o pacote de provedor de fonte, a consulta de fonte e uma lista de conjuntos de hashes para o certificado. Para mais informações sobre FontRequest, consulte a seção Usar o "Fontes para download" de forma programática na documentação Fontes para download.
  2. Crie uma instância de FontRequestEmojiCompatConfig e forneça instâncias de Context e FontRequest.
  3. Inicialize EmojiCompat chamando o método init() e passe a instância de FontRequestEmojiCompatConfig.
  4. Kotlin

    class MyApplication : Application() {
    
        override fun onCreate() {
            super.onCreate()
            val fontRequest = FontRequest(
                    "com.example.fontprovider",
                    "com.example",
                    "emoji compat Font Query",
                    CERTIFICATES
            )
            val config = FontRequestEmojiCompatConfig(this, fontRequest)
            EmojiCompat.init(config)
        }
    }

    Java

    public class MyApplication extends Application {
      @Override
       public void onCreate() {
         super.onCreate();
         FontRequest fontRequest = new FontRequest(
           "com.example.fontprovider",
           "com.example",
           "emoji compat Font Query",
           CERTIFICATES);
         EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
         EmojiCompat.init(config);
       }
    }
  5. Use widgets da EmojiCompat em XMLs de layout. Se você estiver usando AppCompat, consulte a seção Usar widgets da EmojiCompat com AppCompat.
  6. <android.support.text.emoji.widget.EmojiTextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiEditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiButton
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

Para mais informações sobre como definir EmojiCompat com a configuração de fonte disponível para download, acesse a amostra de app Emoji Compatibility (em inglês) Java | Kotlin.

Componentes da biblioteca

Componentes da biblioteca no processo da EmojiCompat
Figura 3. Componentes da biblioteca no processo da EmojiCompat.
Widgets: EmojiEditText, EmojiTextView, EmojiButton
As implementações padrão de widget para usar EmojiCompat com TextView, EditText e Button.
EmojiCompat
Superfície pública principal da Biblioteca de Suporte. Realiza todas as chamadas externas e é coordenada com as outras partes do sistema.
EmojiCompat.Config
Configura a instância singleton a ser criada.
EmojiSpan
Uma subclasse ReplacementSpan que substitui o caractere (sequências) e renderiza o glifo.
Fonte EmojiCompat
EmojiCompat usa uma fonte para exibir emojis. Essa fonte é uma versão modificada da fonte de emojis para Android. A fonte é modificada da seguinte forma:
  • Para oferecer compatibilidade com versões anteriores para renderizar emojis, todos os caracteres de emojis são representados por um único ponto de código Unicode na Área A de Uso Privado Suplementar do Unicode que começa com U+F0001.
  • Outros metadados de emojis são inseridos em um formato binário na fonte e são analisados durante a execução por EmojiCompat. Os dados são incorporados na tabela meta da fonte, com a tag particular Emji.

Opções de configuração

Você pode usar a instância EmojiCompat para modificar o comportamento da EmojiCompat. Use os seguintes métodos da classe básica para definir a configuração:

Kotlin

val config = FontRequestEmojiCompatConfig(...)
        .setReplaceAll(true)
        .setEmojiSpanIndicatorEnabled(true)
        .setEmojiSpanIndicatorColor(Color.GREEN)
        .registerInitCallback(object: EmojiCompat.InitCallback() {
            ...
        })

Java

EmojiCompat.Config config = new FontRequestEmojiCompatConfig(...)
       .setReplaceAll(true)
       .setEmojiSpanIndicatorEnabled(true)
       .setEmojiSpanIndicatorColor(Color.GREEN)
       .registerInitCallback(new InitCallback() {...})

Adicionar listeners de inicialização

As classes EmojiCompat e EmojiCompat fornecem métodos registerInitCallback() e unregisterInitCallback() para registrar um callback de inicialização. Para usar esses métodos, crie uma instância da classe EmojiCompat.InitCallback. Chame esses métodos e passe a instância da classe EmojiCompat.InitCallback. Quando a inicialização da Biblioteca de Suporte EmojiCompat for concluída, a classe EmojiCompat vai chamar o método onInitialized(). Se a biblioteca não for inicializada, a classe EmojiCompat chamará o método onFailed().

Para conferir o estado de inicialização a qualquer momento, chame o método getLoadState(). Ele retorna um dos seguintes valores: LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED ou LOAD_STATE_FAILED.

Usar a EmojiCompat com widgets da AppCompat

Se você estiver usando AppCompat widgets, é possível usar widgets EmojiCompat que se estendem de AppCompat widgets.

  1. Adicione a Biblioteca de Suporte à seção de dependências.

    Groovy

    dependencies {
        ...
        implementation "androidx.emoji:emoji-bundled:$version"
    }

    Kotlin

          dependencies {
              implementation("androidx.emoji:emoji-appcompat:$version")
          }
          

    Groovy

          dependencies {
              implementation "androidx.emoji:emoji-appcompat:$version"
          }
          
  2. Use widgets AppCompat Widget da EmojiCompat em XMLs de layout.
  3. <android.support.text.emoji.widget.EmojiAppCompatTextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiAppCompatEditText
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>
    
    <android.support.text.emoji.widget.EmojiAppCompatButton
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"/>

Configuração de fontes agrupadas

A Biblioteca de Suporte EmojiCompat também está disponível em uma versão de fontes agrupadas. Esse pacote inclui a fonte com os metadados incorporados. O pacote também inclui um BundledEmojiCompatConfig que usa o AssetManager para carregar os metadados e as fontes.

Observação: o tamanho da fonte é de vários megabytes.

Adicionar dependência da Biblioteca de Suporte

Para usar a Biblioteca de Suporte EmojiCompat com a configuração de fontes agrupadas, é necessário modificar as dependências do caminho de classe do projeto do seu app no ambiente de desenvolvimento.

Para adicionar uma Biblioteca de Suporte ao projeto do app:

  1. Abra o arquivo build.gradle do aplicativo.
  2. Adicione a Biblioteca de Suporte à seção dependencies.

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji:emoji:28.0.0")
}

Usar fontes agrupadas para configurar a EmojiCompat

Para usar fontes agrupadas na configuração EmojiCompat, siga as seguintes etapas:

  1. Use BundledEmojiCompatConfig para criar uma instância de EmojiCompat e forneça uma instância de Context.
  2. Chame o método init() para inicializar EmojiCompat e passe a instância de BundledEmojiCompatConfig.

Kotlin

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()
        val config = BundledEmojiCompatConfig(this)
        EmojiCompat.init(config)
    }
}

Java

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
        EmojiCompat.init(config);
        ...
    }
}

Usar a EmojiCompat sem widgets

A EmojiCompat usa EmojiSpan para renderizar imagens corretas. Portanto, ela precisa converter qualquer CharSequence informada em instâncias Spanned com EmojiSpans. A classe EmojiCompat oferece um método para converter CharSequences em instâncias Spanned com EmojiSpans. Usando esse método, é possível processar e armazenar em cache as instâncias processadas em vez da string bruta, o que melhora o desempenho do aplicativo.

Kotlin

val processed = EmojiCompat.get().process("neutral face \uD83D\uDE10")

Java

CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");

Usar a EmojiCompat para Editores de métodos de entrada (IMEs, na sigla em inglês)

Usando a Biblioteca de Suporte EmojiCompat, os teclados podem renderizar os emojis compatíveis com o aplicativo com que estão interagindo. Os IMEs podem usar o método hasEmojiGlyph() para verificar se EmojiCompat é capaz de renderizar um emoji. Esse método usa uma CharSequence de um emoji e retornará true se EmojiCompat puder detectar e renderizar o emoji.

O teclado também pode verificar a versão da Biblioteca de Suporte EmojiCompat compatível com o app para determinar qual emoji renderizar na paleta. Para conferir a versão, se disponível, o teclado precisa consultar se as seguintes chaves existem no pacote EditorInfo.extras:

Depois de receber as chaves no pacote EditorInfo.extras, o teclado pode usar o método hasEmojiGlyph(), em que metadataVersion é o valor de EDITOR_INFO_METAVERSION_KEY, para consultar se o app pode renderizar um emoji específico.

Usar a EmojiCompat com widgets personalizados

Você sempre pode usar o método process() para processar CharSequence previamente no seu app e adicioná-lo a qualquer widget que possa renderizar instâncias Spanned. Por exemplo, TextView. Além disso, EmojiCompat oferece as classes auxiliares de widget a seguir para permitir que você aprimore seus widgets personalizados e ofereça compatibilidade com emojis, com esforço mínimo.

Amostra de TextView

Kotlin

class MyTextView(context: Context) : AppCompatTextView(context) {

    private val emojiTextViewHelper: EmojiTextViewHelper by lazy(LazyThreadSafetyMode.NONE) {
        EmojiTextViewHelper(this).apply {
            updateTransformationMethod()
        }
    }

    override fun setFilters(filters: Array<InputFilter>) {
        super.setFilters(emojiTextViewHelper.getFilters(filters))
    }

    override fun setAllCaps(allCaps: Boolean) {
        super.setAllCaps(allCaps)
        emojiTextViewHelper.setAllCaps(allCaps)
    }
}

Java

public class MyTextView extends AppCompatTextView {
   ...
   public MyTextView(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       getEmojiTextViewHelper().updateTransformationMethod();
   }

   @Override
   public void setFilters(InputFilter[] filters) {
       super.setFilters(getEmojiTextViewHelper().getFilters(filters));
   }

   @Override
   public void setAllCaps(boolean allCaps) {
       super.setAllCaps(allCaps);
       getEmojiTextViewHelper().setAllCaps(allCaps);
   }

   private EmojiTextViewHelper getEmojiTextViewHelper() {
       ...
   }
}
Amostra de EditText

Kotlin

class MyEditText(context: Context) : AppCompatEditText(context) {

    private val emojiEditTextHelper: EmojiEditTextHelper by lazy(LazyThreadSafetyMode.NONE) {
        EmojiEditTextHelper(this).also {
            super.setKeyListener(it.getKeyListener(keyListener))
        }
    }

    override fun setKeyListener(input: KeyListener?) {
        input?.also {
            super.setKeyListener(emojiEditTextHelper.getKeyListener(it))
        }
    }

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        val inputConnection: InputConnection = super.onCreateInputConnection(outAttrs)
        return emojiEditTextHelper.onCreateInputConnection(
                inputConnection,
                outAttrs
        ) as InputConnection
    }
}

Java

public class MyEditText extends AppCompatEditText {
   ...
   public MyEditText(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
   }

   @Override
   public void setKeyListener(android.text.method.KeyListener keyListener) {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
   }

   @Override
   public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
       InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
       return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
   }

   private EmojiEditTextHelper getEmojiEditTextHelper() {
       ...
   }
}

Perguntas frequentes

  • Como iniciar o download de fontes?
  • O download de fontes de emoji é realizado na primeira solicitação, caso elas não existam no dispositivo. A programação de downloads é transparente para o app.

  • Quanto tempo a inicialização leva?
  • Depois do download da fonte, a inicialização da EmojiCompat leva cerca de 150 milésimos de segundo.

  • Quanto de memória a Biblioteca de Suporte EmojiCompat consome?
  • Atualmente, a estrutura de dados para encontrar o emoji é carregada na memória do app e consome cerca de 200 KB.

  • Posso usar a EmojiCompat para um TextView personalizado?
  • Sim. A EmojiCompat oferece classes auxiliares para widgets personalizados. Também é possível processar uma determinada string previamente e convertê-la em Spanned. Para mais informações sobre classes auxiliares de widget, consulte a seção Usar a EmojiCompat com widgets personalizados.

  • O que acontecerá se eu adicionar widgets em XMLs de layout em dispositivos com o Android 4.4 (API de nível 19) ou versões anteriores?
  • Você pode incluir a Biblioteca de Suporte EmojiCompat ou os widgets dela nos aplicativos compatíveis com os dispositivos com o Android 4.4 (API de nível 19) ou versões anteriores. No entanto, se um dispositivo usar uma versão do Android anterior à API de nível 19, a EmojiCompat e os widgets relacionados ficarão em um estado “sem operação”. Isso significa que o EmojiTextView se comporta exatamente como uma instância TextView. EmojiCompat comum, ou seja, ele entra imediatamente no estado LOAD_STATE_SUCCEEDED quando você chama o método init().

Outros recursos

Para mais informações sobre como usar a biblioteca EmojiCompat, assista EmojiCompat (em inglês).