Android——Youmeng som de notificação personalizado

Recentemente, recebi uma solicitação, como o título, para adicionar uma voz personalizada ao Youmeng Push.
insira a descrição da imagem aqui
A descrição é bem concisa, como pode ser visto na figura acima, o foco deste requisito é a compatibilidade de versões acima de 8.0. O código de amostra fornecido por Youmeng é o seguinte:
insira a descrição da imagem aqui
A partir do código acima, ele está realmente definindo uma notificação personalizada, mas o código acima não é viável para sistemas acima de 8.0. O motivo deve ser claro para todos. Um recurso NotificationChannel foi adicionado à barra de notificação acima de 8.0. Se o canal de notificação do canal não estiver definido, a notificação não será exibida.

definir som local

Agora vamos voltar ao foco do nosso requisito desta vez: personalizar o som. Pela análise acima, já sabemos que o som personalizado do Umeng é na verdade uma notificação personalizada, então o som personalizado também faz parte da notificação personalizada, como fazer isso? O método pode ser encontrado procurando na API do NotificationChannel setSound(Uri sound, AudioAttributes audioAttributes). Então se apresse e faça o upload do código, vamos configurar um som local primeiro:

//Android 8.0 以上需包添加渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
	NotificationChannel notificationChannel = new NotificationChannel(newChannel, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
	Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.ding);
	//只能在create一个渠道之前修改铃声,在创建之后不支持修改
	notificationChannel.setSound(sound, Notification.AUDIO_ATTRIBUTES_DEFAULT);

	manager.createNotificationChannel(notificationChannel);
}

Nota:
Preste atenção especial aos comentários no código acima aqui. Você só pode modificar o toque antes de criar um canal e não suporta modificações após a criação. A descrição foi dada nos comentários do método
de razão específica :setSound
insira a descrição da imagem aqui

som configurável

Vendo que algumas pessoas podem ter dúvidas aqui, o que devo fazer se quiser alterar o som e tornar o som personalizado configurável? ? ?

Como um NotificationChannel só pode vincular um som, podemos criar um novo canal para vincular um novo som? A resposta é sim. Como o som anterior não é mais usado, precisamos excluir (deleteNotificationChannel(String channelId)) o NotificationChannel anterior. Há um buraco aqui. Quando você o excluirá? Para o primeiro teste, criei um novo canal ao modificar o toque ou a vibração, e apaguei todos os canais antigos antes, mas haverá um bug neste modo, a Notificação que ainda é exibida na barra de status no canal anterior será ser excluído, todos Faça um julgamento, se o canal atual não tiver notificação exibida na barra de status, exclua-o, caso contrário, continue salvando, o código é o seguinte:

Nota:
Para adicionar aqui, o método deleteNotificationChannel realmente não exclui o canal, mas apenas define um sinalizador de exclusão. O processo de análise específico pode ser visto no código-fonte PreferencesHelper.deleteNotificationChannel().

private static void deleteNoNumberNotification(NotificationManager nm, String newChannelId) {
	List<NotificationChannel> notificationChannels = nm.getNotificationChannels();
	if (Utils.isEmpty(notificationChannels) || notificationChannels.size() < 5) {
		return;
	}
	
	for (NotificationChannel channel : notificationChannels) {
		if (channel.getId() == null || channel.getId().equals(newChannelId)) {
			continue;
		}

		int notificationNumbers = getNotificationNumbers(nm, channel.getId());
		Logger.i(TAG, "notificationNumbers: " + notificationNumbers + " channelId:" + channel.getId());
		if (notificationNumbers == 0) {
			Log.i(TAG, "deleteNoNumberNotification: " + channel.getId());
            nm.deleteNotificationChannel(channel.getId());
        }
    }
}

 /**
  * 获取某个渠道下状态栏上通知显示个数
  *
  * @param mNotificationManager NotificationManager
  * @param channelId            String
  * @return int
  */
@RequiresApi(api = Build.VERSION_CODES.O)
private static int getNotificationNumbers(NotificationManager mNotificationManager, String channelId) {
	if (mNotificationManager == null || TextUtils.isEmpty(channelId)) {
		return -1;
	}
	int numbers = 0;
	StatusBarNotification[] activeNotifications = mNotificationManager.getActiveNotifications();
	for (StatusBarNotification item : activeNotifications) {
		Notification notification = item.getNotification();
        if (notification != null) {
        	if (channelId.equals(notification.getChannelId())) {
            	numbers++;
            }
        }
    }
    return numbers;
}

Os itens acima são todos os problemas de personalização do som local, então alguém tem outro problema.Se eu quiser configurar um áudio de rede, como devo configurá-lo? ? ?

Configurar áudio de rede

Consulte o método getSound de UmengMessageHandler no Umeng SDK:
insira a descrição da imagem aquiinsira a descrição da imagem aqui
Se for áudio de rede, Umeng primeiro baixa o arquivo de áudio para o diretório de cache local e, em seguida, o define.

Aqui eu tive uma ideia preguiçosa no começo, já que Youmeng considerou tão bem para nós, posso usar este método getSound diretamente? Através do experimento, infelizmente, o som não foi reproduzido diretamente pelo método de Youmeng. Aqui está um grande ponto de interrogação para todos. Se algum parceiro souber o motivo, por favor, comente e compartilhe para discutirmos juntos.

Como não é confiável usar diretamente as notícias de Youmeng, você só pode fazê-lo diretamente.De acordo com as ideias fornecidas por Youmeng, baixe o arquivo para o local e configure-o. O diretório que baixei aqui é getExternalCacheDir(), e é estranho que ele possa ser reproduzido ( •̀ ω •́ )y.

Uma pequena análise da reprodução de áudio de notificação

Aqui está outro a acrescentar: Quando não consegui descobrir por que o arquivo baixado de Youmeng não podia ser reproduzido, tive uma ideia preguiçosa de definir diretamente o endereço de áudio http para Uri. O teste descobriu que o endereço Https pode ser reproduzido no celular Xiaomi. Os endereços Http não podem ser reproduzidos. Vamos falar sobre isso aqui, na verdade, isso não é uma solução, ou mesmo uma abordagem errada. por que?

A reprodução do som da notificação é implementada na classe NotificationPlayer, veja o código:
insira a descrição da imagem aqui
a reprodução do som final ainda é realizada pelo MediaPlayer. O som que definimos para a notificação antes é o DataSource do MediaPlayer. Se for um áudio de rede e depois agrupado por Uri, o player pensará que é um arquivo local e relatará um erro de arquivo não encontrado ao analisar. É incrível. Aqui é claramente um erro, mas você ainda pode ouvir o som tocando em alguns telefones celulares. Portanto, não é recomendável conectar diretamente o endereço Http ao Sound.

Como a parte do código-fonte mencionada acima é apenas um determinado ponto, se você precisar conhecer mais alunos, abra o código-fonte para comparação e compreensão detalhadas.

O código-fonte deste artigo é o seguinte:

public static String UMENG_INTERNET_SOUND_DOWNPATH = MyApplication.getInstance().getExternalCacheDir() +  "/sound_cache";

//8.0版本以上自定义通知兼容
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
	mPushAgent.setMessageHandler(messageHandler);
}

//自定义消息进行处理
private static UmengMessageHandler messageHandler = new UmengMessageHandler() {

	@Override
    public void dealWithNotificationMessage(Context context, UMessage uMessage) {
		if (uMessage.hasResourceFromInternet() && !MessageSharedPrefs.getInstance(context).hasMessageResourceDownloaded(uMessage.msg_id)) {
        	downInternetSound(context, uMessage);
            return;
        }
        super.dealWithNotificationMessage(context, uMessage);
    }

    @Override
    public Uri getSound(Context context, UMessage uMessage) {
		return getCustomSound(context, uMessage);
    }

    @Override
    public Notification getNotification(Context context, UMessage uMessage) {

        if (uMessage.builder_id == 1) {
			long curTime = System.currentTimeMillis();
            String CHANNEL_ID = AppUtils.getAppName();//应用频道Id唯一值, 长度若太长可能会被截断,
            String newChannel = CHANNEL_ID + curTime;
            String CHANNEL_NAME = AppUtils.getAppName();//最长40个字符,太长会被截断

			Uri sound = getSound(context, uMessage);

            Intent hangIntent = new Intent(context, MainActivity.class);
            PendingIntent hangPendingIntent = PendingIntent.getActivity(context, 1001, hangIntent,  PendingIntent.FLAG_UPDATE_CURRENT);

            Notification notification = new NotificationCompat.Builder(context, newChannel)
                        .setContentTitle(uMessage.title)
                        .setContentText(uMessage.text)
                        .setSmallIcon(R.mipmap.app_logo)
                        .setContentIntent(hangPendingIntent)
                        //.setFullScreenIntent(hangPendingIntent,true)
                        .setSound(sound)
                        .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_logo))
                        .setAutoCancel(true)
                        .build();

            //Android 5.0 以上锁屏通知
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            	notification.visibility = Notification.VISIBILITY_PUBLIC;
            }

            //Android 8.0 以上需包添加渠道
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            	NotificationManager manager =  (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

                //只能在create一个渠道之前修改铃声,在创建之后不支持修改
                //只能去重新创建一个渠道设置铃声振动
                //对于之前创建的渠道,通过deleteNotificationChannel(String channelId)去删除
                List<NotificationChannel> channelList = manager.getNotificationChannels();
                if (channelList != null && channelList.size() > 0) {
                	for (NotificationChannel channel : channelList) {
                    	if (!TextUtils.isEmpty(channel.getId()) && channel.getId().startsWith(CHANNEL_ID)) {
                        	manager.deleteNotificationChannel(channel.getId());
                        }
                    }
                }

                NotificationChannel notificationChannel = new NotificationChannel(newChannel, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
                //只能在create一个渠道之前修改铃声,在创建之后不支持修改
                notificationChannel.setSound(sound, Notification.AUDIO_ATTRIBUTES_DEFAULT);

                manager.createNotificationChannel(notificationChannel);
		}

        Log.d("umeng", "notificationDefault: " + getNotificationDefaults(context, uMessage));

        return notification;
            }
        //默认为0,若填写的builder_id并不存在,也使用默认。
        return super.getNotification(context, uMessage);
    }
};

    /**
     * 自定义通知声音
     *
     * @param context
     * @param uMessage
     * @return
     */
    private static Uri getCustomSound(Context context, UMessage uMessage) {
        String soundPath = uMessage.sound;

        try {
            if (soundPath == null) {
                int assetsSound = com.umeng.message.common.d.a(context).j("umeng_push_notification_default_sound");

                if (assetsSound > 0) {
                    soundPath = "android.resource://" + context.getPackageName() + "/" + assetsSound;
                }
            } else {
                if (uMessage.isSoundFromInternet()) {
                    soundPath = UMENG_INTERNET_SOUND_DOWNPATH + "/" + uMessage.sound.hashCode();
                } else {
                    int assetsSound = com.umeng.message.common.d.a(context).j(uMessage.sound);

                    if (assetsSound > 0) {
                        soundPath = "android.resource://" + context.getPackageName() + "/" + assetsSound;
                    }
                }
            }

            if (soundPath != null) {
                Uri soundUri = Uri.parse(soundPath);
                return soundUri;
            }
        } catch (Throwable throwable) {
            throwable.toString();
        }
        return null;
    }

    private static void downInternetSound(Context context, UMessage uMessage) {
        String downPath = UMENG_INTERNET_SOUND_DOWNPATH;
        String downFileName = uMessage.sound.hashCode() + "";
        OkGoRequest.downLoad(context, uMessage.sound, new FileCallback(downPath, downFileName) {
            @Override
            public void onSuccess(Response<File> response) {
                MessageSharedPrefs.getInstance(context).setMessageResourceDownloaded(uMessage.msg_id);
                messageHandler.dealWithNotificationMessage(context, uMessage);
            }

            @Override
            public void onError(Response<File> response) {
                super.onError(response);
                MessageSharedPrefs.getInstance(context).setMessageResourceDownloaded(uMessage.msg_id);
                messageHandler.dealWithNotificationMessage(context, uMessage);
            }
        });
    }

O código fornece apenas ideias e você mesmo pode escrever o código completo para a implementação específica.

Reabastecimento:

Recentemente, descobri que há um som personalizado do telefone celular no Android 11 que não emite som. Abra a configuração do toque na configuração do sistema e descubra que não há toque de notificação, o que é bastante estranho. Um colega propôs um esquema de toque personalizado que imita o QQ e o WeChat e usa o MediaPlayer para tocar música sozinho. Essa também é uma solução. Os alunos que encontrarem esse problema podem experimentá-lo.

Acho que você gosta

Origin blog.csdn.net/u012230055/article/details/117032246
Recomendado
Clasificación