Flutter Plugin For Importing Stickers Into Telegram
Tags: flutter, telegram, opensource
Published: 2021-06-30 08:55:47

Telegram recently has announced a [new contest](https://t.me/contest/262).

**Given**: a sticker import mechanism for Android and iOS apps.

**Task**: write an Android or iOS app that uses this mechanism.

The timing is very limited, the deadline is the 4th of July. Objectively, I don't have time to write an app in such a short time. I decided to help the Flutter developers in this contest and write a plugin to work with the native SDK. The article will dwell on that.

Let's see what kind of import mechanism Telegram offers us.

## Android

The official repository is [here](https://github.com/DrKLO/TelegramStickersImport). There is no SDK. To import stickers, you just need to send Intent with a set of parameters. What could be easier?

```java
Intent intent = new Intent(CREATE_STICKER_PACK_ACTION);
intent.putExtra(Intent.EXTRA_STREAM, stickers);
intent.putExtra(CREATE_STICKER_PACK_IMPORTER_EXTRA, getPackageName());
intent.putExtra(CREATE_STICKER_PACK_EMOJIS_EXTRA, emojis);
intent.setType("image/*");
```

The difficulty is that you need to give permission to a third-party application so it can get access to any of your files (we are not considering the raw directory case). You can read more about file sharing between applications in [official documentation](https://developer.android.com/training/secure-file-sharing/setup-sharing).

Use [FileProvider](https://developer.android.com/reference/androidx/core/content/FileProvider) to allow access to your files. Basically, we describe which directories we want to give access to, and also describe the name that will hide the real path to the files.

For simplicity, I've prepared one folder in the directory with the cache. In case if you want to use some other folder, you will need to configure the manifest:

```xml
...
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>
...
```

and add an xml file describing the available paths:

```xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <cache-path path="telegram_stickers_import/" name="telegram_stickers_import" />
</paths>
```

When used in this way, the path:

`/data/user/0/com.otopba.telegram_stickers_import_example/cache/telegram_stickers_import/sticker1.webp`

Turns into:

`content://com.otopba.telegram_stickers_import_example.provider/telegram_stickers_import/sticker1.webp`

## iOS

The official repository is [here](https://github.com/TelegramMessenger/TelegramStickersImport). Telegram provides SDK for iOS and has even made data validation with human-readable errors.

You need to add a few lines to `Info.plist` to make it work:

```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>tg</string>
</array>
```

## How to use the plugin

As expected, the plugin is as simple as possible: one method where you need to pass your stickerset for import:

```dart
class TelegramStickersImport {
  /// Folder inside cache directory for store your stickers
  static const androidImportFolderName = "telegram_stickers_import";

  static const MethodChannel _channel = MethodChannel(
    'telegram_stickers_import',
  );

  /// Method for import sticker set
  static Future<String?> import(StickerSet stickerSet) async {
    return _channel.invokeMethod('import', stickerSet.toMap());
  }
}
```

The nuance is in reading the sticker files:

- to run the Android app, you will need to copy your stickers files to the `cache/telegram_stickers_import` folder (or one that you set up by yourself);
- for the iOS application, you will need to read the contents of the stickers into the `Uint8List`.

```dart
StickerData({this.path, this.bytes});

/// Android factory
factory StickerData.android(String path) {
  return StickerData(path: path);
}

/// iOS factory
factory StickerData.iOS(Uint8List bytes) {
  return StickerData(bytes: bytes);
}
```

## Conclusion

It's strange that Telegram made an SDK only for iOS, and Android developers, as always, should do their rain dance. 

I will be glad if you use [my plugin](https://github.com/otopba/telegram_stickers_import).

I'm looking forward to the Pull Requests.

Ciao!