Condividi tramite


Inviare notifiche alle applicazioni Android e iOS

Questo articolo offre una panoramica dell'applicazione di esempio hub di notifica di Azure creata per illustrare le funzionalità dell'hub di notifica di Azure su più piattaforme. L'applicazione usa uno scenario di sondaggio sul territorio, in cui l'applicazione Desktop Contoso Land Survey invia notifiche, che possono ricevere sia le applicazioni Android che iOS Contoso.

È possibile scaricare l'esempio completo da GitHub.

Prerequisiti

Per compilare l'esempio, sono necessari i prerequisiti seguenti:

  • Una sottoscrizione di Azure. Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.
  • Microsoft Visual Studio 2019 o versione successiva. Questo esempio usa Visual Studio 2019.
  • Visual Studio 2019 con i carichi di lavoro seguenti installati:
  • Account Firebase per abilitare le notifiche push per Android.
  • Account sviluppatore Apple per abilitare le notifiche push per iOS.
  • Un'istanza del database di SQL Server ospitata in Azure.
  • Uno spazio dei nomi e un hub di Hub di notifica di Azure.

Architettura di esempio

La soluzione è costituita dai componenti seguenti:

  • Istanza dell'hub di notifica di Azure: uno spazio dei nomi ANH e un hub configurati nel portale di Azure.
  • Database di SQL Server: un'istanza del database di SQL Server configurata nel portale di Azure.
  • ASP.NET back-end dell'app: un back-end api Web basato su .NET 5.0, che si connette all'hub di notifica ed è ospitato come servizio app Azure.
  • Applicazione UWP di Windows: un'applicazione UWP creata con React Native e funge da applicazione "manager" che invia notizie e informazioni di sondaggio a vari utenti e gruppi di sondaggi. L'applicazione consente anche di creare nuovi utenti e di modificare i gruppi a cui viene assegnato un utente.
  • App client Android e iOS: applicazioni "Land Survey" create con React Native. Queste app mostrano agli utenti le informazioni inviate dall'applicazione di gestione UWP.

Struttura di cartelle di esempio

L'applicazione di esempio in GitHub contiene le cartelle seguenti:

  • NotificationHub.Sample.API: una soluzione API Web di Visual Studio 2019 ASP.NET che funge da back-end.
  • app: un'applicazione React Native multipiattaforma che consente di inviare notifiche con un account di accesso del manager e quindi di ricevere notifiche con un account di accesso utente del sondaggio.
  • azure-template: modelli di Azure Resource Manager (parameters.json e template.json) che è possibile usare per distribuire tutte le risorse necessarie per configurare questa distribuzione nella sottoscrizione di Azure. Per altre informazioni sulla distribuzione dei modelli di Resource Manager, vedere Creare e distribuire modelli di Resource Manager usando il portale di Azure.

Panoramica dell'esempio

Le sezioni seguenti forniscono una panoramica dei componenti che costituiscono l'esempio.

Controller

Autenticazione

I metodi seguenti in AuthenticateController.cs vengono usati per autenticare un utente connesso:

[HttpPost]
[Route("login")]
public async Task<IActionResult> Login([FromBody] LoginModel model)
{
   var user = await userManager.FindByNameAsync(model.Username);
    if (user != null && await userManager.CheckPasswordAsync(user, model.Password))
    {
        var userRoles = await userManager.GetRolesAsync(user);

        var authClaims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, user.UserName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        };

        foreach (var userRole in userRoles)
        {
            authClaims.Add(new Claim(ClaimTypes.Role, userRole));
        }

        var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));

        var token = new JwtSecurityToken(
            issuer: _configuration["JWT:ValidIssuer"],
            audience: _configuration["JWT:ValidAudience"],
            expires: DateTime.Now.AddHours(3),
            claims: authClaims,
            signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
            );

        UserDetails userDetails = new UserDetails();
        userDetails.FirstName = model.Username;
        userDetails.LastName = model.Username;
        userDetails.UserName = model.Username;

        return Ok(new
        {
            token = new JwtSecurityTokenHandler().WriteToken(token),
            expiration = token.ValidTo,
            username = model.Username,
            email = user.Email,
            role = userRoles != null ? userRoles[0] : "Site-Manager",
            user = userDetails
        });
    }
    return Unauthorized();
}

[HttpPost]
[Route("register")]
public async Task<IActionResult> Register([FromBody] RegisterModel model)
{
    var userExists = await userManager.FindByNameAsync(model.Username);
    if (userExists != null)
        return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User already exists!" });

    ApplicationUser user = new ApplicationUser()
    {
        Email = model.Email,
        SecurityStamp = Guid.NewGuid().ToString(),
        UserName = model.Username
    };
    var result = await userManager.CreateAsync(user, model.Password);
    if (!result.Succeeded)
        return StatusCode(StatusCodes.Status500InternalServerError, new Response { Status = "Error", Message = "User creation failed! Please check user details and try again." });

    if (!await roleManager.RoleExistsAsync(UserRoles.SiteManager))
        await roleManager.CreateAsync(new IdentityRole(UserRoles.SiteManager));

    if (await roleManager.RoleExistsAsync(UserRoles.SiteManager))
    {
        await userManager.AddToRoleAsync(user, UserRoles.SiteManager);
    }

    return Ok(new Response { Status = "Success", Message = "User created successfully!" });
}

Dashboard

Il controller del dashboard in DashboardController.cs restituisce tutte le informazioni di notifica:

public class DashboardController : ControllerBase
{
    private readonly ApplicationDbContext _db;
    private readonly INotificationService _notificationService;

    public DashboardController(ApplicationDbContext dbContext, INotificationService notificationService)
    {
        _db = dbContext;
        _notificationService = notificationService;
    }

    [HttpGet("insights")]
    public async Task<IActionResult> GetDashboardInsight(string duration)
    {
        DashboardInsight dashboardInsight = new DashboardInsight();

        dashboardInsight.DeviceTrends = await _notificationService.GetAllRegistrationInfoAsync();

        var notificationMessages = _db.NotificationMessages.ToList();

        switch (duration)
        {
            case "Daily":
                {
                    dashboardInsight.NotificationTrends = _db.NotificationMessages
                                                            .GroupBy(m => m.SentTime.Date)
                                                            .Select(m => new NotificationTrend()
                                                            {
                                                                Timestamp = m.Key.ToShortDateString(),
                                                                NotificationsSent = m.Count()
                                                            }).ToList();
                }
                break;
            case "Weekly":
                {
                    dashboardInsight.NotificationTrends = notificationMessages
                                                            .GroupBy(m => WeekNumber(m.SentTime.Date))
                                                            .Select(m => new NotificationTrend()
                                                            {
                                                                Timestamp = FirstDateOfWeekISO8601(DateTime.Now.Year, m.Key).ToShortDateString(),
                                                                NotificationsSent = m.Count()
                                                            }).ToList();
                }
                break;
            case "Monthly":
                {
                    dashboardInsight.NotificationTrends = _db.NotificationMessages
                                                            .GroupBy(m => m.SentTime.Date.Month)
                                                            .Select(m => new NotificationTrend()
                                                            {
                                                                Timestamp = m.Key + "-" + DateTime.Now.Year,
                                                                NotificationsSent = m.Count()
                                                            }).ToList();
                }
                break;
            default:
                break;
        }

        dashboardInsight.TotalGroups = _db.SurveyGroups.Count();
        dashboardInsight.TotalUsers = _db.Users.Count();
        dashboardInsight.TotalNotificationsSent = _db.NotificationMessages.Count();

        return Ok(dashboardInsight);
    }

Front-end

Per chiamare qualsiasi API back-end, l'esempio crea il servizio notification.service.js, che effettua una chiamata API effettiva. Questo codice si trova in app\data\services\notification.service.js:

export const sendNotificationAPI = async (userInfo) => {
  let url = `${api}notification/send`;
  let authHeader = await getAuthHeaders();
  return await post(url, userInfo, { ...authHeader });
};

export const getNotificationsAPI = async () => {
  let url = `${api}notification/get`;
  let authHeader = await getAuthHeaders();
  return await get(url, { ...authHeader });
};

Applicazione manager

Questo esempio include un'applicazione UWP compilata con React Native, che funge da applicazione "manager" che invia notizie e informazioni sui sondaggi a vari utenti e gruppi di sondaggi. L'applicazione consente anche di creare nuovi utenti e di modificare i gruppi a cui è assegnato un utente.

Per l'account di accesso del manager, usare l'endpoint e il corpo POST seguenti per generare le credenziali utente desiderate. È possibile usare qualsiasi client REST HTTP di propria scelta:

Endpoint

POST {{endpoint}}api/authenticate/register-admin

Testo

{
  "username": "<USER_NAME>",
  "email": "<EMAIL>",
  "password": "<PASSWORD>"
}

Dopo la registrazione, si dovrebbe essere in grado di accedere all'applicazione UWP con le stesse credenziali.

Controller di notifica

Il codice seguente, in NotificationController.cs, ottiene e invia notifiche:

[Produces("application/json")]
[Consumes("application/json")]
[HttpPost("send")]
public async Task<ActionResult> SendNotification([FromBody] NotificationMessage notificationMessage)
{
    try
    {
        List<string> tags = new List<string>();

        // attach survey group and user information with notificationMessage
        notificationMessage.SurveyGroupTags.ForEach(surveyGroupId =>
        {
            var group = _db.SurveyGroups.Where(g => g.Id == surveyGroupId).FirstOrDefault();
            if (group != null)
            {
                notificationMessage.SurveyGroups.Add(group);
                tags.Add($"group:{group.GroupName.Replace(' ', '-')}");
            }
        });

        notificationMessage.UserTags.ForEach(userId =>
        {
            var user = _db.Users.Where(u => u.Id == userId).FirstOrDefault();
            if (user != null)
            {
                notificationMessage.Users.Add(user);
                tags.Add($"username:{user.UserName}");
            }
        });
        _db.NotificationMessages.Add(notificationMessage);

        // send template notification
        var notification = new Dictionary<string, string>();
        notification.Add("title", notificationMessage.NotificationTitle);
        notification.Add("message", notificationMessage.NotificationDescription);

        var res = await _notificationService.RequestNotificationAsync(notificationMessage, tags, HttpContext.RequestAborted);

        await _db.SaveChangesAsync();
        return Ok(notificationMessage);
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

[Produces("application/json")]
[HttpGet("get")]
public async Task<ActionResult> Get()
{
    try
    {
        var surveyGroups = _db.NotificationMessages.Include(message => message.SurveyGroups).Include(message => message.Users).ToList();
        return Ok(surveyGroups);
    }
    catch (Exception ex)
    {
        return BadRequest();
    }
}

Servizio di notifica

Il servizio di notifica situato in NotificationHub.Sample.API/NotificationHub.Sample.API/Services/Notifications/INotificationService.cs include metodi per creare ed eliminare l'installazione. Esiste anche un metodo per inviare notifiche a tutti gli utenti registrati e per ottenere tutte le informazioni di registrazione:

public interface INotificationService
{
   Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken cancellationToken);
   Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken cancellationToken);
   Task<bool> RequestNotificationAsync(NotificationMessage notificationMessage, IList<string> tags, CancellationToken cancellationToken);
   Task<List<DeviceTrend>> GetAllRegistrationInfoAsync();
}

Distribuire la soluzione

Per eseguire l'esempio, sono necessari i prerequisiti seguenti:

  • Una sottoscrizione di Azure. Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito.
  • Account Firebase per configurare le notifiche push per Android.
  • Account sviluppatore Apple per configurare le notifiche push per iOS.
  • Un computer Windows con Visual Studio 2019 installato, insieme al supporto per lo sviluppo di applicazioni UWP e Core ASP.NET.
  • Android SDK e Android Studio nel computer di sviluppo se si esegue l'applicazione Android.
  • Un computer Mac OSX con XCode e l'SDK iOS più recente, se si esegue l'applicazione iOS.

Distribuire le risorse

  • Istanza di Hub di notifica di Azure: un hub di notifica configurato in Azure.
  • Istanza del database di SQL Server: un database di SQL Server ospitato in Azure.
  • back-end dell'app ASP.NET: back-end dell'API Web compilato su .NET 5.0, che si connette all'hub di notifica di Azure ospitato come servizio app Azure. Per altre informazioni, vedere Guida introduttiva: Distribuire un'app Web ASP.NET.

Se non si vogliono distribuire manualmente tutte le risorse, è possibile usare il file di Azure Resource Manager template.json fornito nel repository GitHub per distribuire tutte le istanze necessarie in un unico passaggio. Il file modello è disponibile nel repository in /azure-template. Per altre informazioni su come usare i modelli di Resource Manager, vedere Esercitazione: Usare i modelli di avvio rapido di Azure.

Configurare le notifiche per Android e iOS

  • Firebase: per ricevere notifiche in Android, configurare il servizio Firebase e connetterlo all'istanza dell'hub di notifica di Azure. Per altre informazioni, vedere Configurare le impostazioni di Google Firebase.
  • Apple Push Notification Service (APNS): per ricevere notifiche in iOS, configurare il servizio APNS usando l'account sviluppatore Apple e connetterlo all'istanza dell'hub di notifica di Azure. Per altre informazioni, vedere Configurare le impostazioni di Apple Push Notification Service.

Compilare la soluzione

Per compilare l'esempio, seguire questa procedura.

Creare una risorsa: database SQL

Creare un'istanza di database di SQL Server nel portale di Azure. Ad esempio:

Risorse dell'istanza DI SQL

Modello di distribuzione

Creare una risorsa: hub di notifica

Creare un hub di notifica nel portale di Azure come indicato di seguito:

  1. Accedere al portale di Azure.

  2. Scegliere Tutti i servizi dal menu a sinistra. Screenshot che mostra la selezione di Tutti i servizi per uno spazio dei nomi esistente.

  3. Digitare Hub di notifica nella casella di testo Filtri servizi. Selezionare l'icona a forma di stella accanto al nome del servizio per aggiungere il servizio alla sezione PREFERITI nel menu a sinistra. Selezionare Hub di notifica.

    Screenshot che mostra come filtrare gli hub di notifica.

  4. Nella pagina Hub di notifica selezionare Crea sulla barra degli strumenti.

    Screenshot che mostra come creare un nuovo hub di notifica.

  5. Nella scheda Informazioni di base della pagina hub di notifica seguire questa procedura:

    1. In Sottoscrizioneselezionare il nome della sottoscrizione di Azure che si vuole usare e quindi selezionare un gruppo di risorse esistente o crearne uno nuovo.

    2. Immettere un nome univoco per il nuovo spazio dei nomi in Dettagli spazio dei nomi.

    3. Uno spazio dei nomi contiene uno o più hub di notifica, quindi digitare un nome per l'hub in Dettagli hub di notifica.

    4. Selezionare un valore nell'elenco a discesa Posizione. Questo valore specifica la posizione in cui creare l'hub.

      Screenshot che mostra i dettagli dell'hub di notifica.

    5. Esaminare l'opzione Zone di disponibilità. Se si sceglie un'area con zone di disponibilità, la casella di controllo è selezionata per impostazione predefinita. Le zone di disponibilità sono una funzionalità a pagamento, quindi viene aggiunta una tariffa aggiuntiva al livello.

    6. Scegliere un'opzione di ripristino di emergenza: Nessuna, area di ripristino abbinata o area di ripristino flessibile. Se si sceglie Area di ripristino abbinata, viene visualizzata l'area di failover. Se si seleziona Area di ripristino flessibile, usare l'elenco a discesa per scegliere tra un elenco di aree di ripristino.

      Screenshot che mostra i dettagli della zona di disponibilità.

    7. Seleziona Crea.

  6. Una volta completata la distribuzione, selezionare Vai alla risorsa.

Configurare il back-end

Per configurare il back-end dell'app, individuare il file /NotificationHub.Sample.API/appsettings.json e configurare il stringa di connessione di SQL Server.

È possibile eseguire la soluzione API in locale o in qualsiasi server IIS oppure distribuirla come servizio app Web di Azure. Tenere a portata di mano l'URL dell'API.

Compilare l'applicazione NotificationHub.Sample.API

  1. In Visual Studio caricare la soluzione /NotificationHubSample/NotificationHub.Sample.API/NotificationHub.Sample.API.sln.

  2. Dal menu Compila scegliere Compila soluzione.

  3. Pubblicare la soluzione in Azure: in Esplora soluzioni fare clic con il pulsante destro del mouse sul progetto NotificationHub.Sample.API e quindi scegliere Pubblica.

  4. Nella finestra di dialogo Pubblica selezionare Azure (prima opzione), quindi selezionare Avanti.

  5. Selezionare app Azure Servizio (Windows) e quindi selezionare Avanti.

  6. Si viene reindirizzati alla finestra di dialogo seguente, da cui è possibile selezionare il nome della sottoscrizione e le istanze di AppService appropriati. Il back-end verrà distribuito in Azure e verrà reindirizzato a un nuovo URL.

    Pubblicazione del progetto

  7. Dopo la pubblicazione del back-end, aggiungere l'URL generato in config.js, che si trova nella cartella /app . Assicurarsi di aggiungere /api/ dopo l'URL.

Eseguire l'applicazione front-end React Native per Windows

L'applicazione richiede sia l'applicazione per dispositivi mobili (Android o iOS) sia l'applicazione di gestione UWP in esecuzione contemporaneamente. Seguire questi passaggi per eseguirli entrambi:

Aprire la cartella dell'app nella finestra del terminale o della shell preferita. Procedere quindi come segue:

Finestre

  1. Eseguire npm install per installare tutte le dipendenze del pacchetto.
  2. Eseguire npm run start per avviare il server metro in una finestra della console.
  3. Aprire un'altra finestra del terminale ed eseguire npx react-native run-windows per eseguire l'applicazione UWP.
  4. Se la distribuzione o la compilazione non riesce, vedere la guida alla risoluzione dei problemi.

Android

  1. Configurare Firebase nel progetto React-Native per assicurarsi di poter usare le funzionalità di notifica.
  2. Dopo aver configurato correttamente il progetto Firebase, scaricare il file google-services.json dal portale firebase.
  3. Sostituire ./app/android/app/google-services.json con questo nuovo file. Assicurarsi che il nome del pacchetto dell'applicazione corrisponda a quello configurato in Firebase. Il nome del pacchetto viene configurato nel file AndroidManifest.xml .
  4. Per altre informazioni su come configurare le notifiche in un'applicazione React Native, vedere Esercitazione: Inviare notifiche push a React Native.
  5. Dopo aver configurato le notifiche, eseguire npm run start per avviare il server metro in una finestra della console. Se l'applicazione Windows è già in esecuzione, è possibile ignorare questo passaggio.
  6. In una nuova finestra della console eseguire npx react-native run-android per eseguire l'applicazione Android.

iOS

  1. Configurare APNS nel progetto React-Native per assicurarsi di poter usare le funzionalità di notifica.
  2. In iOS le notifiche possono essere ricevute solo dalle applicazioni firmate e installate tramite App Store o TestFlight. È necessario creare un'applicazione nell'account per sviluppatore Apple. L'identificatore bundle dell'applicazione configurato nell'account per sviluppatore Apple deve essere configurato nei file Info.plist e Entitlements.plist dell'applicazione.
  3. Per altre informazioni su come configurare le notifiche in un'applicazione React Native, vedere Esercitazione: Inviare notifiche push a React Native.
  4. Dopo aver configurato le notifiche, eseguire npm run start per avviare il server metro in una finestra della console. Se l'applicazione Windows è già in esecuzione, è possibile ignorare questo passaggio.
  5. In una nuova finestra della console eseguire npx react-native run-ios per eseguire l'applicazione iOS. Come accennato in precedenza, le notifiche non funzioneranno in iOS se distribuite in locale. Non è possibile ricevere notifiche nel simulatore iOS.

Risoluzione dei problemi

È possibile che venga visualizzato l'errore seguente durante l'esecuzione dell'applicazione React Native for Windows:

error MSB4057: The target "Deploy" does not exist in the project

Si tratta di un problema noto con React Native per Windows. Per risolvere questo problema, scaricare il file con estensione csproj per i progetti CheckboxWindows e ReactNativeAsyncStorage in Visual Studio dopo aver aperto app.sln nella cartella app/windows . Quindi, nel file app.csproj aggiungere la riga seguente subito prima ...</Project>di , quindi ricaricare il progetto:

<Target Name="Deploy"/>

Passaggi successivi