Changeant de Windows Phone, je me suis posé la question sur le backup/restore d’un téléphone à un autre. Malheureusement, pas de possibilité de sauvegarder/backuper les données de mes applications/jeux.
Sur ce constat, j’ai exploré les possibilités pour m’appuyer sur SkyDrive. En effet, mon téléphone est connecté, via mon Live ID, sur les services Live de Microsoft. Donc, pourquoi ne pas permettre de faire un export de mes données sur SkyDrive, afin de les importer ultérieurement…
Première étape : visualiser mes fichiers sur SkyDrive depuis mon PC. Ayant trouvé un tutorial sur « MonWindowsPhone.com », je ne vais pas m’étendre plus sur le sujet, et je vous conseille d’aller jeter un œil sur l’article d’Arnaud Deschamps de MonWindowsPhone. Il explique comment accéder à SkyDrive depuis son PC sans passer via un browser, ainsi que des intégrations de SkyDrive dans les applications “standard” du Windows Phone.
Deuxième étape : télécharger les Tools et SDK. Via le lien suivant, le SDK est téléchargeable, et la documentation disponible. Une documentation plus spécifique est disponible ici.
Troisième étape : expérimenter l’accès à SkyDrive depuis mon Windows Phone.
Avant d’interagir avec les services Live, il faut s’authentifier. L’objet LiveAuthClient effectue cette opération en affichant à l’utilisateur un écran demandant le nom d’utilisateur et le mot de passe.
Remarque : l’authentification est interactive ! Donc pas moyen de faire une connexion dans un « Background Agent ». Il faut que la partie graphique de l’application soit initialisée, donc pas d’authentification dans les fonctions « Application_Launching », …
Le premier paramètre de LiveAuthClient définit l’identification du client (« ClientID »). Vous pouvez en générer un en suivant ce lien suivant : https://manage.dev.live.com/. Dans mon code exemple, je mets la valeur "1234567890123456". L’event LoginCompleted retourne à l’application le résultat de l’authentification.
LiveAuthClient lac = new LiveAuthClient("1234567890123456", "http://oauth.live.com/desktop");
private void button1_Click(object sender, RoutedEventArgs e)
{
lac.LoginCompleted +=new EventHandler<LoginCompletedEventArgs>(lac_LoginCompleted);
List<String> l = new List<string>() { "wl.basic", "wl.photos", "wl.skydrive", "wl.offline_access", "wl.signin", "wl.skydrive_update"};
lac.LoginAsync(l);
}
void lac_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
}
Après l’authentification, l’accès aux fichiers. On énumère les objets dans la racine « me/skydrive » du SkyDrive. Le suffixe « /files » permet de récupérer les éléments.
private void EnumRootFolder_Click(object sender, RoutedEventArgs e)
{
LiveConnectClient clientFolder = new LiveConnectClient(lac.Session);
clientFolder.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(clientFolder_GetCompleted);
clientFolder.GetAsync("me/skydrive/files");
}
En retour les services live renvoient la liste des éléments sous forme d’un fichier JSON. Ci-dessous une partie du résultat. (Les “------------ “ remplacent mes identifiants uniques)
|
{
"data": [
{
"id": "folder. ------------.------------",
"from": {
"name": "Christophe Peerens",
"id": "------------"
},
"name": "Les puces et le chocolas",
"description": "",
"parent_id": "folder. ------------",
"upload_location": "https://apis.live.net/v5.0/folder. ------------.------------!116/files/",
"is_embeddable": true,
"count": 1,
"link": "https://skydrive.live.com/redir.aspx?cid\u003d------------\u0026page\u003dview\u0026resid\u003d------------!116\u0026parid\u003d------------!136",
"type": "album",
"shared_with": {
"access": "People with a link"
},
"created_time": "2007-01-02T13:58:27+0000",
"updated_time": "2011-04-02T07:27:55+0000"
}, {
"id": "folder. ------------.------------!137",
"from": {
"name": "Christophe Peerens",
"id": "------------"
},
"name": "Public",
"description": null,
"parent_id": "folder. ------------",
"upload_location": "https://apis.live.net/v5.0/folder. ------------.------------!137/files/",
"is_embeddable": true,
"count": 1,
"link": "https://skydrive.live.com/redir.aspx?cid\u003d------------\u0026page\u003dview\u0026resid\u003d------------!137\u0026parid\u003d------------!136",
"type": "folder",
"shared_with": {
"access": "Everyone (public)"
},
"created_time": "2009-01-25T13:21:27+0000",
"updated_time": "2011-05-18T07:08:33+0000"
}, {
…
}, {
…
}, {
…
}, {
…
}
]
}
|
Dans l’event handler, le paramètre e donne le fichier JSON en format RAW, mais aussi une interprétation sous forme de collection de celui-ci. Une petite gymnastique de casting, et les informations sont disponibles.
void clientFolder_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
if (e.Result != null)
{
foreach (var o in e.Result)
{
foreach (var oo in ((System.Collections.Generic.List<object>)(o.Value)))
{
System.Collections.Generic.Dictionary<string, object> entry = (System.Collections.Generic.Dictionary<string, object>)oo;
String id = (string)entry["id"];
String name = (string)entry["name"];
String type = (string)entry["type"];
}
}
}
}
Ci-dessous le code complet qui permet de naviguer dans les répertoires SkyDrive.
XAML:
<phone:PhoneApplicationPage
x:Class="SkyDriveExplorer.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox ItemsSource="{Binding}" Margin="0,0,0,0" Name="lstFolder" SelectionChanged="lstFolder_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Margin="0,0,0,0" FontWeight="Bold"/>
<TextBlock Text="{Binding Id}" TextWrapping="Wrap" Margin="20,0,0,0" />
<TextBlock Text="{Binding Type}" TextWrapping="Wrap" Margin="20,0,0,0" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
Code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Live;
using Microsoft.Phone.Controls;
namespace SkyDriveExplorer
{
public partial class MainPage : PhoneApplicationPage
{
public class SkyDriveListBoxItem : INotifyPropertyChanged, INotifyPropertyChanging
{
private String _Id;
public String Id
{
get
{
return _Id;
}
set
{
NotifyPropertyChanging("Id");
_Id = value;
NotifyPropertyChanged("Id");
}
}
private String _Name;
public String Name
{
get
{
return _Name;
}
set
{
NotifyPropertyChanging("Name");
_Name = value;
NotifyPropertyChanged("Name");
}
}
private String _Type;
public String Type
{
get
{
return _Type;
}
set
{
NotifyPropertyChanging("Type");
_Type = value;
NotifyPropertyChanged("Type");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
public ObservableCollection<SkyDriveListBoxItem> folderitems = new ObservableCollection<SkyDriveListBoxItem>();
public MainPage()
{
InitializeComponent();
DataContext = folderitems;
}
String strFolderName = "me/skydrive";
// replace de CID
static LiveAuthClient lac = new LiveAuthClient("0000000099999999", "http://oauth.live.com/desktop");
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
}
private void Login()
{
lac.LoginCompleted += new EventHandler<LoginCompletedEventArgs>(lac_LoginCompleted);
List<String> l = new List<string>() { "wl.basic", "wl.photos", "wl.skydrive", "wl.offline_access", "wl.signin", "wl.skydrive_update" };
lac.LoginAsync(l);
}
void lac_LoginCompleted(object sender, LoginCompletedEventArgs e)
{
if (e.Status == LiveConnectSessionStatus.Connected)
{
ScanFolder();
}
}
void ScanFolder()
{
LiveConnectClient clientFolder = new LiveConnectClient(lac.Session);
clientFolder.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(clientFolder_GetCompleted);
clientFolder.GetAsync(strFolderName+"/files");
}
void clientFolder_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
{
if (e.Result != null)
{
Dispatcher.BeginInvoke(() =>
{
folderitems.Clear();
foreach (var o in e.Result)
{
foreach (var oo in ((System.Collections.Generic.List<object>)(o.Value)))
{
System.Collections.Generic.Dictionary<string, object> entry = (System.Collections.Generic.Dictionary<string, object>)oo;
folderitems.Add( new SkyDriveListBoxItem() { Id = (string)entry["id"], Name = (string)entry["name"], Type = (string)entry["type"] } );
}
}
});
}
}
private void lstFolder_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lstFolder.SelectedIndex == -1)
{
return;
}
if ((((SkyDriveListBoxItem)lstFolder.SelectedItem).Type == "folder") || (((SkyDriveListBoxItem)lstFolder.SelectedItem).Type == "album"))
{
NavigationService.Navigate(new Uri("/MainPage.xaml?folderid=" + ((SkyDriveListBoxItem)lstFolder.SelectedItem).Id, UriKind.RelativeOrAbsolute));
}
lstFolder.SelectedIndex = -1;
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
if (lac.Session == null)
{
Login();
}
else
{
String strParamFolderName = "";
if (NavigationContext.QueryString.TryGetValue("folderid", out strParamFolderName))
{
strFolderName = strParamFolderName;
ScanFolder();
}
}
}
}
}