Android: sonido de notificación personalizado de Youmeng

Recientemente, recibí una solicitud, como el título, para agregar una voz personalizada a Youmeng Push.
inserte la descripción de la imagen aquí
La descripción es muy concisa.Como se puede ver en la figura anterior, el enfoque de este requisito es la compatibilidad de las versiones superiores a la 8.0. El código de muestra proporcionado por Youmeng es el siguiente:
inserte la descripción de la imagen aquí
del código anterior, en realidad está configurando una notificación personalizada, pero el código anterior no es factible para sistemas superiores a 8.0. El motivo debe ser claro para todos. Se ha agregado una función de NotificationChannel a la barra de notificaciones por encima de 8.0. Si el canal de notificación del canal no está configurado, la notificación no se mostrará.

establecer sonido local

Ahora volvamos al foco de nuestro requerimiento esta vez: personalizar el sonido. A través del análisis anterior, ya sabemos que el sonido personalizado de Umeng es en realidad una notificación personalizada, por lo que el sonido personalizado también es parte de la notificación personalizada, ¿cómo hacerlo? El método se puede encontrar buscando en la API de NotificationChannel setSound(Uri sound, AudioAttributes audioAttributes). Así que date prisa y sube el código, primero configuremos un sonido local:

//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 especial atención a los comentarios en el código anterior aquí. Solo puede modificar el tono de llamada antes de crear un canal, y no admite la modificación después de la creación. La descripción se ha dado en los comentarios del método
de razón específica :setSound
inserte la descripción de la imagen aquí

sonido configurable

Al ver que algunas personas pueden tener preguntas aquí, ¿qué debo hacer si quiero cambiar el sonido y hacer que el sonido personalizado sea configurable? ? ?

Dado que un canal de notificación solo puede vincular un sonido, ¿podemos crear un nuevo canal para vincular un nuevo sonido? La respuesta es sí. Dado que el sonido anterior ya no se usa, debemos eliminar (deleteNotificationChannel(String channelId)) el canal de notificación anterior. Aquí hay un hoyo. ¿Cuándo lo eliminará? Para la primera prueba, creé un nuevo canal al modificar el tono de llamada o la vibración, y eliminé todos los canales antiguos antes, pero habrá un error de esta manera, la Notificación que aún se muestra en la barra de estado del canal anterior ser eliminado, todo Haga un juicio, si el canal actual no tiene ninguna notificación mostrada en la barra de estado, elimínelo, de lo contrario continúe guardando, el código es el siguiente:

Nota:
Para agregar aquí, el método deleteNotificationChannel en realidad no elimina el canal, sino que solo establece un indicador de eliminación. El proceso de análisis específico se puede ver en el código fuente 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;
}

Los anteriores son todos los problemas de personalizar el sonido local, entonces alguien tiene otro problema.Si quiero configurar un audio en red, ¿cómo debo configurarlo? ? ?

Configurar el audio de la red

Consulte el método getSound de UmengMessageHandler en Umeng SDK:
inserte la descripción de la imagen aquíinserte la descripción de la imagen aquí
si se trata de audio de red, Umeng primero descarga el archivo de audio en el directorio de caché local y luego lo configura.

Aquí tuve una idea vaga al principio, ya que Youmeng lo ha considerado tan bien para nosotros, ¿puedo usar este método getSound directamente? Desafortunadamente, a través del experimento, el sonido no se reprodujo directamente con el método de Youmeng. Aquí hay un gran signo de interrogación para todos. Si algún compañero sabe el motivo, comente y compártalo para discutirlo juntos.

Dado que no es confiable usar directamente las noticias de Youmeng, solo puede hacerlo directamente. De acuerdo con las ideas proporcionadas por Youmeng, descargue el archivo en el local y luego configúrelo. El directorio que descargué aquí es getExternalCacheDir(), y es extraño que se pueda reproducir ( •̀ ω •́ )y.

Un pequeño análisis de la reproducción de audio de notificación

Aquí hay otro para agregar: Cuando no pude encontrar por qué no se podía reproducir el archivo descargado de Youmeng, tuve la vaga idea de configurar directamente la dirección de audio http en Uri. La prueba encontró que la dirección Https se puede reproducir en el teléfono móvil Xiaomi Las direcciones HTTP no se pueden reproducir. Hablemos de eso aquí, de hecho, esta no es una solución, ni siquiera un enfoque incorrecto. ¿por qué?

La reproducción del sonido de notificación se implementa en la clase NotificationPlayer, consulte el código:
inserte la descripción de la imagen aquí
MediaPlayer aún realiza la reproducción final del sonido. El sonido que configuramos para la notificación antes es la fuente de datos de MediaPlayer. Si es audio de red y luego envuelto por Uri, el reproductor pensará que es un archivo local e informará un error de archivo no encontrado al analizarlo. Es increíble. Aquí es claramente un error, pero aún puede escuchar el sonido reproduciéndose en algunos teléfonos móviles. Por lo tanto, no se recomienda conectar directamente la dirección Http a Sound.

Dado que la parte del código fuente mencionada anteriormente es solo un punto determinado, si necesita conocer a más estudiantes, abra el código fuente para una comparación y comprensión detalladas.

El código fuente de este artículo es el siguiente:

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);
            }
        });
    }

El código solo proporciona ideas y usted mismo puede escribir el código completo para la implementación específica.

Reponer:

Recientemente, descubrí que hay un sonido personalizado de teléfono móvil en Android 11 que no emite ningún sonido. Abra la configuración del tono de llamada en la configuración del sistema y descubra que no hay tono de llamada de notificación, lo cual es bastante extraño. Un colega propuso un esquema de tono de llamada personalizado que imita a QQ y WeChat, y usa MediaPlayer para reproducir música por sí mismo. Esta también es una solución. Los estudiantes que encuentren este problema pueden probarlo.

Supongo que te gusta

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