我正在研究whatsapp贴纸。我已经尝试过这个演示 https://github.com/viztushar/stickers-internet。同样使用相同的数据,我可以在演示中添加贴纸,但在我的代码中不起作用。
内容提供类:
public class StickerContentProvider extends ContentProvider {
/**
* Do not change the strings listed below, as these are used by WhatsApp. And changing these will break the interface between sticker app and WhatsApp.
*/
public static final String STICKER_PACK_IDENTIFIER_IN_QUERY = "sticker_pack_identifier";
public static final String STICKER_PACK_NAME_IN_QUERY = "sticker_pack_name";
public static final String STICKER_PACK_PUBLISHER_IN_QUERY = "sticker_pack_publisher";
public static final String STICKER_PACK_ICON_IN_QUERY = "sticker_pack_icon";
public static final String ANDROID_APP_DOWNLOAD_LINK_IN_QUERY = "android_play_store_link";
public static final String IOS_APP_DOWNLOAD_LINK_IN_QUERY = "ios_app_download_link";
public static final String PUBLISHER_EMAIL = "sticker_pack_publisher_email";
public static final String PUBLISHER_WEBSITE = "sticker_pack_publisher_website";
public static final String PRIVACY_POLICY_WEBSITE = "sticker_pack_privacy_policy_website";
public static final String LICENSE_AGREENMENT_WEBSITE = "sticker_pack_license_agreement_website";
public static final String STICKER_FILE_NAME_IN_QUERY = "sticker_file_name";
public static final String STICKER_FILE_EMOJI_IN_QUERY = "sticker_emoji";
public static final String CONTENT_FILE_NAME = "contents.json";
public static final String CONTENT_SCHEME = "content";
private static final String TAG = StickerContentProvider.class.getSimpleName();
public static Uri AUTHORITY_URI = new Uri.Builder().scheme(StickerContentProvider.CONTENT_SCHEME).authority(BuildConfig.CONTENT_PROVIDER_AUTHORITY).appendPath(StickerContentProvider.METADATA).build();
/**
* Do not change the values in the UriMatcher because otherwise, WhatsApp will not be able to fetch the stickers from the ContentProvider.
*/
private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static final String METADATA = "metadata";
private static final int METADATA_CODE = 1;
private static final int METADATA_CODE_FOR_SINGLE_PACK = 2;
static final String STICKERS = "stickers";
private static final int STICKERS_CODE = 3;
static final String STICKERS_ASSET = "stickers_asset";
private static final int STICKERS_ASSET_CODE = 4;
private static final int STICKER_PACK_TRAY_ICON_CODE = 5;
private List<StickerPack> stickerPackList = new ArrayList<>();
@Override
public boolean onCreate() {
Hawk.init(getContext()).build();
final String authority = BuildConfig.CONTENT_PROVIDER_AUTHORITY;
if (!authority.startsWith(Objects.requireNonNull(getContext()).getPackageName())) {
throw new IllegalStateException("your authority (" + authority + ") for the content provider should start with your package name: " + getContext().getPackageName());
}
//the call to get the metadata for the sticker packs.
MATCHER.addURI(authority, METADATA, METADATA_CODE);
//the call to get the metadata for single sticker pack. * represent the identifier
MATCHER.addURI(authority, METADATA + "/*", METADATA_CODE_FOR_SINGLE_PACK);
//gets the list of stickers for a sticker pack, * respresent the identifier.
MATCHER.addURI(authority, STICKERS + "/*", STICKERS_CODE);
for (StickerPack stickerPack : getStickerPackList()) {
Log.e(TAG, "onCreate: " + stickerPack.identifier);
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + stickerPack.tray_image_file, STICKER_PACK_TRAY_ICON_CODE);
if (stickerPack.getStickers() != null) {
for (Sticker sticker : stickerPack.getStickers()) {
MATCHER.addURI(authority, STICKERS_ASSET + "/" + stickerPack.identifier + "/" + sticker.image_file, STICKERS_ASSET_CODE);
}
}
}
return true;
}
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
final int code = MATCHER.match(uri);
Log.d(TAG, "query: " + code + uri);
if (code == METADATA_CODE) {
return getPackForAllStickerPacks(uri);
} else if (code == METADATA_CODE_FOR_SINGLE_PACK) {
return getCursorForSingleStickerPack(uri);
} else if (code == STICKERS_CODE) {
return getStickersForAStickerPack(uri);
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
@Nullable
@Override
public AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
MATCHER.match(uri);
final int matchCode = MATCHER.match(uri);
final List<String> pathSegments = uri.getPathSegments();
Log.d(TAG, "openFile: " + matchCode + uri + "\n" + uri.getAuthority()
+ "\n" + pathSegments.get(pathSegments.size() - 3) + "/"
+ "\n" + pathSegments.get(pathSegments.size() - 2) + "/"
+ "\n" + pathSegments.get(pathSegments.size() - 1));
return getImageAsset(uri);
}
private AssetFileDescriptor getImageAsset(Uri uri) throws IllegalArgumentException {
AssetManager am = Objects.requireNonNull(getContext()).getAssets();
final List<String> pathSegments = uri.getPathSegments();
if (pathSegments.size() != 3) {
throw new IllegalArgumentException("path segments should be 3, uri is: " + uri);
}
String fileName = pathSegments.get(pathSegments.size() - 1);
final String identifier = pathSegments.get(pathSegments.size() - 2);
if (TextUtils.isEmpty(identifier)) {
throw new IllegalArgumentException("identifier is empty, uri: " + uri);
}
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("file name is empty, uri: " + uri);
}
//making sure the file that is trying to be fetched is in the list of stickers.
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
if (fileName.equals(stickerPack.tray_image_file)) {
return fetchFile(uri, am, fileName, identifier);
} else {
for (Sticker sticker : stickerPack.getStickers()) {
if (fileName.equals(sticker.image_file)) {
return fetchFile(uri, am, fileName, identifier);
}
}
}
}
}
return null;
}
private AssetFileDescriptor fetchFile(@NonNull Uri uri, @NonNull AssetManager am, @NonNull String fileName, @NonNull String identifier) {
try {
File file;
if(fileName.endsWith(".png")){
file = new File(getContext().getFilesDir()+ "/" + "stickers_asset" + "/" + identifier + "/try/", fileName);
} else {
file = new File(getContext().getFilesDir()+ "/" + "stickers_asset" + "/" + identifier + "/", fileName);
}
if (!file.exists()) {
Log.d("fetFile", "StickerPack dir not found");
}
Log.d("fetchFile", "StickerPack " + file.getPath());
return new AssetFileDescriptor(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY), 0L, -1L);
} catch (IOException e) {
Log.e(Objects.requireNonNull(getContext()).getPackageName(), "IOException when getting asset file, uri:" + uri, e);
return null;
}
}
@Override
public String getType(@NonNull Uri uri) {
final int matchCode = MATCHER.match(uri);
switch (matchCode) {
case METADATA_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case METADATA_CODE_FOR_SINGLE_PACK:
return "vnd.android.cursor.item/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + METADATA;
case STICKERS_CODE:
return "vnd.android.cursor.dir/vnd." + BuildConfig.CONTENT_PROVIDER_AUTHORITY + "." + STICKERS;
case STICKERS_ASSET_CODE:
return "image/webp";
case STICKER_PACK_TRAY_ICON_CODE:
return "image/png";
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
private synchronized void readContentFile(@NonNull Context context) {
if (Hawk.get("sticker_pack", new ArrayList<StickerPack>()) != null) {
stickerPackList.addAll(Hawk.get("sticker_pack", new ArrayList<StickerPack>()));
}
}
public List<StickerPack> getStickerPackList() {
/* if (stickerPackList == null) {
readContentFile(Objects.requireNonNull(getContext()));
}*/
return (List)Hawk.get("sticker_packs",new ArrayList<StickerPack>());
}
private Cursor getPackForAllStickerPacks(@NonNull Uri uri) {
return getStickerPackInfo(uri, getStickerPackList());
}
private Cursor getCursorForSingleStickerPack(@NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
return getStickerPackInfo(uri, Collections.singletonList(stickerPack));
}
}
return getStickerPackInfo(uri, new ArrayList<StickerPack>());
}
@NonNull
private Cursor getStickerPackInfo(@NonNull Uri uri, @NonNull List<StickerPack> stickerPackList) {
MatrixCursor cursor = new MatrixCursor(
new String[]{
STICKER_PACK_IDENTIFIER_IN_QUERY,
STICKER_PACK_NAME_IN_QUERY,
STICKER_PACK_PUBLISHER_IN_QUERY,
STICKER_PACK_ICON_IN_QUERY,
ANDROID_APP_DOWNLOAD_LINK_IN_QUERY,
IOS_APP_DOWNLOAD_LINK_IN_QUERY,
PUBLISHER_EMAIL,
PUBLISHER_WEBSITE,
PRIVACY_POLICY_WEBSITE,
LICENSE_AGREENMENT_WEBSITE
});
for (StickerPack stickerPack : stickerPackList) {
MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(stickerPack.identifier);
builder.add(stickerPack.name);
builder.add(stickerPack.publisher);
builder.add(stickerPack.tray_image_file);
builder.add(stickerPack.androidPlayStoreLink);
builder.add(stickerPack.iosAppStoreLink);
builder.add(stickerPack.publisher_email);
builder.add(stickerPack.publisher_website);
builder.add(stickerPack.privacy_policy_website);
builder.add(stickerPack.license_agreement_website);
}
Log.d(TAG, "getStickerPackInfo: " + stickerPackList.size());
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
@NonNull
private Cursor getStickersForAStickerPack(@NonNull Uri uri) {
final String identifier = uri.getLastPathSegment();
MatrixCursor cursor = new MatrixCursor(new String[]{STICKER_FILE_NAME_IN_QUERY, STICKER_FILE_EMOJI_IN_QUERY});
for (StickerPack stickerPack : getStickerPackList()) {
if (identifier.equals(stickerPack.identifier)) {
for (Sticker sticker : stickerPack.getStickers()) {
cursor.addRow(new Object[]{sticker.image_file, TextUtils.join(",", sticker.emojis)});
}
}
}
cursor.setNotificationUri(Objects.requireNonNull(getContext()).getContentResolver(), uri);
return cursor;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException("Not supported");
}
@Override
public int update(@NonNull Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
throw new UnsupportedOperationException("Not supported");
}
}
如果需要任何其他代码,请告诉我。
错误跟踪:
IOException when getting asset file, uri:content://com.mercatus.shoppers.stag.provider.StickerContentProvider/stickers_asset/1/69DEA9206D7A4EDF8D8E6439B41BBBB4.ashx
java.io.FileNotFoundException: open failed: ENOENT (No such file or directory)
at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:313)
at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:211)
at com.mall.provider.StickerContentProvider.fetchFile(StickerContentProvider.java:187)
at com.mall.provider.StickerContentProvider.getImageAsset(StickerContentProvider.java:162)
at com.mall.provider.StickerContentProvider.openAssetFile(StickerContentProvider.java:140)
at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1746)
at android.content.ContentProvider.openTypedAssetFile(ContentProvider.java:1812)
at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:425)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:302)
at android.os.Binder.execTransact(Binder.java:739)
错误 :
文件位置: