Comment obtenir un fichier apk depuis un appareil Android?


484

Comment puis-je obtenir le fichier apk à partir d'un appareil Android? Ou comment transférer le fichier apk de l'appareil vers le système?

Réponses:


119

Utilisez adb . Avec adb pull, vous pouvez copier des fichiers de votre appareil vers votre système, lorsque l'appareil est connecté via USB.

Bien sûr, vous avez également besoin des autorisations appropriées pour accéder au répertoire dans lequel se trouve votre fichier. Sinon, vous devrez d'abord rooter le périphérique.


Si vous constatez que de nombreux fichiers APK sont nommés "base.apk", vous pouvez également utiliser cette commande d'une ligne pour extraire tous les fichiers APK d'un téléphone auquel vous pouvez accéder tout en renommant tous les noms "base.apk" en nom de package. Cela corrige également le problème de répertoire introuvable pour les chemins APK avec des caractères apparemment aléatoires après le nom:

for i in $(adb shell pm list packages | awk -F':' '{print $2}'); do adb pull "$(adb shell pm path $i | awk -F':' '{print $2}')"; mv base.apk $i.apk 2&> /dev/null ;done

Si vous obtenez "adb: erreur: n'a pas réussi à stat objet distant" qui indique que vous ne disposez pas des autorisations nécessaires. Je l'ai exécuté sur un Moto Z2 NON rooté et j'ai pu télécharger TOUS les APK que je n'ai pas désinstallés (voir ci-dessous) sauf YouTube.

adb shell pm uninstall --user 0 com.android.cellbroadcastreceiver   <--- kills presidential alert app!

(pour afficher les utilisateurs exécutent adb shell pm liste les utilisateurs) C'est un moyen de supprimer / désinstaller (pas du téléphone car il revient avec la réinitialisation d'usine) presque TOUTE application SANS racine INCLUANT les applications système (faites allusion à l'application de mise à jour ennuyeuse qui met à jour votre téléphone la ligne ou non peut être trouvée en cherchant "ccc")


1
Merci Maurits Rijk. Veuillez m'aider. Je souhaite copier le fichier iTwips.apk de l'appareil vers le système. J'utilise la commande suivante. est-ce correct ? J'ai l'erreur "Android2.2Froyo / sdcard / iTwips.apk" ne se termine pas ... / Users / bbb / Android / android-sdk-mac_86 / tools / adb pull Android2.2Froyo / sdcard / iTwips.apk / Users / bbb Merci d'avance .......
Finder

Sur mon appareil (Android 2.1), la commande serait "adb pull /sdcard/test.jpg" pour copier test.jpg de ma carte SD vers le répertoire courant. Veuillez d'abord localiser votre fichier iTwips.apk en utilisant "adb shell". Cela démarre un shell sur votre appareil et vous pouvez utiliser les commandes Unix standard comme ls et cd pour parcourir vos répertoires.
Maurits Rijk

Salut, En fait, le iTwips.apk stocké dans la mémoire interne de l'appareil. comment puis-je utiliser le shell pour celui-ci? J'utilise la commande suivante adp -d <devicenumber> shell .. Mais cela ne fonctionne pas .. veuillez m'aider .. Merci d'avance.
Finder

Salut, merci beaucoup. Je peux obtenir les images de la carte SD maintenant. mais je veux extraire le fichier apk de l'appareil (dossier managementApplication). L'apk iTwips est stocké dans le dossier Application. Veuillez m'aider.
Finder

16
@Finder @Maurits Rijk En fait, vous n'avez pas à rooter l'appareil juste pour tirer l'apk. Tant que vous connaissez le chemin complet de cette apk. Si l'apk est installé, trouvez le chemin complet en regardant d'abord le nom du paquet avec adb shell pm list packages, puis son chemin complet adb shell pm path your.package.namedepuis votre PC, vous pouvez simplementadb pull /full/path/to/your.apk
Isa A

1550

Aucune de ces suggestions n'a fonctionné pour moi, car Android ajoutait un numéro de séquence au nom du package pour produire le nom de fichier APK final. Sur les versions plus récentes d'Android (Oreo et Pie), une chaîne aléatoire imprévisible est ajoutée. La séquence de commandes suivante est ce qui a fonctionné pour moi sur un appareil non rooté :

1) Déterminez le nom du package de l'application, par exemple "com.example.someapp". Ignorez cette étape si vous connaissez déjà le nom du package.

adb shell pm list packages

Parcourez la liste des noms de packages et essayez de trouver une correspondance entre l'application en question et le nom du package. C'est généralement facile, mais notez que le nom du package peut être complètement indépendant du nom de l'application. Si vous ne pouvez pas reconnaître l'application dans la liste des noms de packages, essayez de trouver l'application dans Google Play à l'aide d'un navigateur. L'URL d'une application dans Google Play contient le nom du package.

2) Obtenez le nom de chemin complet du fichier APK pour le package souhaité.

adb shell pm path com.example.someapp

La sortie ressemblera à quelque chose
package: /data/app/com.example.someapp-2.apk
ou
package: /data/app/com.example.someapp-nfFSVxn_CTafgra3Fr_rXQ == / base.apk

3) En utilisant le nom de chemin complet de l'étape 2, tirez le fichier APK de l'appareil Android vers la boîte de développement.

adb pull /data/app/com.example.someapp-2.apk path/to/desired/destination

65
C'est la meilleure réponse, pas besoin de faire tourner l'appareil !! merci beaucoup
Muhannad A.Alhariri

14
Cela a fonctionné sur tous mes appareils Android et devrait être la réponse acceptée.
b.mcewan

8
pm list packagesprend en charge le -fdrapeau, qui répertorie l'emplacement du .apk pour vous, comme package:/data/app/com.google.android.apps.maps-1.apk=com.google.android.apps.maps. L'aide intégrée de pm est inutile, mais pm peut également filtrer les types de packages, voir developer.android.com/studio/command-line/adb.html#pm pour plus d'informations. EDIT: vient de remarquer que la réponse ci-dessous dit cela, mais cette réponse n'est pas aussi bien votée que celle-ci.
Hitechcomputergeek

9
Ça ne marche pas pour moi. Je reçois l'erreur suivante: adb: error: remote object '/data/app/path.of.the.app-2/base.apk' does not exist. Si je parcours ces dossiers avec un explorateur de fichiers, les dossiers sont vides.
Bevor

8
J'ai eu un problème similaire à @Bevor, lorsque j'ai tiré, j'ai eu l'erreur que l'apk "n'existe pas". Je l'ai corrigé en utilisant adb shellpuis cp PathToApk /sdcard/, puis en copiant à partir de la carte SD.
colin

124

Aucune racine n'est requise:

Ce code obtiendra le chemin des packages tiers avec le nom afin que vous puissiez facilement identifier votre APK

adb shell pm list packages -f -3

la sortie sera

package: /data/app/XX.XX.XX.apk=YY.YY.YY

tirez maintenant ce paquet en utilisant le code ci-dessous:

adb pull /data/app/XX.XX.XX.apk

si vous avez exécuté au-dessus de cmd in C:>\, vous y trouverez ce package.


1
C'est une réponse géniale! Merci beaucoup :)
Drag0

1
Pour une raison quelconque, je ne trouve pas les fichiers APK dans mon répertoire / data / app / . Il y a toujours un sous-répertoire.
IgorGanapolsky

pour les applications système, utilisez -f -sau lieu de-f -3
palindrom

57

J'ai vu que de nombreuses solutions à ce problème, soit vous devez rooter votre téléphone ou vous devez installer une application. Ensuite, après beaucoup de recherches sur Google, j'ai obtenu cette solution pour les téléphones non rootés / rootés.

Pour répertorier les applications que vous avez obtenues jusqu'à présent.

adb shell pm list packages

Ensuite, vous pouvez sélectionner une application, par exemple Twitter

adb backup -apk com.twitter.android

Une chose importante ici est de ne pas configurer de mot de passe pour crypter votre sauvegarde

Cela va créer un fichier nommé backup.ap, mais vous ne pouvez toujours pas l'ouvrir. Pour cela, vous devez l'extraire à nouveau, mais en utilisant la commande dd.

dd if=backup.ab bs=24 skip=1 | openssl zlib -d > backup.tar

Après cela, tout ce que vous avez à faire est d'extraire le contenu du goudron et c'est fait.

J'espère que cela fonctionne pour vous les gars


7
Depuis blog.shvetsov.com/2013/02/… , si votre openssl n'a pas zlib, cela pourrait fonctionner: dd if = backup.ab bs = 1 skip = 24 | python -c "importer zlib, sys; sys.stdout.write (zlib.decompress (sys.stdin.read ()))" | tar -xvf -
kodi

1
C'est ce qui a fonctionné pour moi, pas la procédure dans la réponse acceptée. Et cela m'a vraiment aidé aujourd'hui lorsque j'avais besoin de l'APK d'une de mes anciennes applications, mais il n'était pas disponible pour moi autrement que depuis mon téléphone.
zeeshan

1
Voici plus d'informations si votre openssl ne prend pas en charge zlib: stackoverflow.com/questions/29830981/…
Nico Wiedemann

19

Étapes pour télécharger l'APK de l'appareil vers le bureau

A) Assurez-vous que votre fonctionnement (émulateur / appareil réel). Pour vérifier, utilisez cette commande

adb devices

B) Sélectionnez toute la liste des packages disponibles installée sur votre appareil. Vous pouvez utiliser la commande grep pour sélectionner le package spécifique que vous souhaitez télécharger.

adb shell pm list packages
adb shell pm list packages -f -3

Sortie (Liste des packages disponibles)

package:/data/app/com.example.mytestapplication-sOzKi5USzfbYLPNDmaaK6g==/base.apk=com.example.mytestapplication
package:/data/app/com.example.myapplication-nd1I4FGnTZnQ9PyRbPDHhw==/base.apk=com.example.myapplication

C) Copiez le package (que vous souhaitez télécharger) à partir du lien ci-dessus. Dans notre cas, je choisis ce package (com.example.myapplication)

Syntax : adb shell pm path [your_package_name]
Command: adb shell pm path com.example.myapplication

Production

package:/data/app/com.example.myapplication-nd1I4FGnTZnQ9PyRbPDHhw==/base.apk

D) Enfin, pour télécharger l'APK de votre (émulateur / appareil réel)

Syntax : adb pull /data/app/[your_package_name]-1/base.apk  [your_destination_path]
Command: adb pull /data/app/com.example.myapplication-3j4CVk0Tb2gysElgjz5O6A==/base.apk /Users/$(whoami)/Documents/your_apk.apk

Exemple: essayer d'extraire ce fichier CertInstaller.apk sur votre ordinateur local (Mac)

adb pull /system/app/CertInstaller/CertInstaller.apk /Users/$(whoami)/Documents/APK/download_apk/

E) Confirmez dans votre annuaire local

ls -la /Users/$(whoami)/Documents/

L'objectif est d'extraire une seule apk, mais à l'étape 4, vous tirez deux fichiers supplémentaires sans explication ni référence précédente.
Carles Alcolea

J'ai modifié ce message en clarifiant chaque étape. J'espère que cette modification sera utile et facile à comprendre.
Farid Haq

18
C:\Users\xyz>adb shell pm list packages -f | findstr whatsapp
package:/data/app/com.whatsapp-1/base.apk=com.whatsapp

C:\Users\xyz>adb pull /data/app/com.whatsapp-1/base.apk Desktop
/data/app/com.whatsapp-1/base.apk: 1 f.... 13.8 MB/s (32803925 bytes in 
2.269s)

À mon avis, c'est la manière la plus simple. Merci!
8bitcartridge

1
les gars utilisant linux ou mac au lieu de findstr utilisent grep
Jeeva

10

Un liner qui fonctionne pour toutes les versions d'Android:

adb shell 'cat `pm path com.example.name | cut -d':' -f2`' > app.apk

1
@AlexP. qu'avez-vous voulu dire par le lien ci-dessus?
Vitaly Dyatlov

7

En complétant la réponse de @Yojimbo, voici ce que j'ai fait (Linux / Mac uniquement, ne fonctionnera pas prêt à l'emploi sur Windows ... peut-être dans le shell bash de git):

for i in $(adb shell pm list packages -f -3 | cut -d= -f 1 | cut -d ":" -f 2); do adb pull $i; done

C'est moche bash, mais ça marche :)

EDIT: Cela ne fonctionne plus sur AndroidM: tous les fichiers sont nommés "base.apk" sous un autre répertoire. Doit être «trivial» à corriger.


7

Sur les systèmes Unix, vous pouvez essayer cette fonction:

function android_pull_apk() {
    if [ -z "$1" ]; then
        echo "You must pass a package to this function!"
        echo "Ex.: android_pull_apk \"com.android.contacts\""
        return 1
    fi

    if [ -z "$(adb shell pm list packages | grep $1)" ]; then
        echo "You are typed a invalid package!"
        return 1
    fi

    apk_path="`adb shell pm path $1 | sed -e 's/package://g' | tr '\n' ' ' | tr -d '[:space:]'`"
    apk_name="`adb shell basename ${apk_path} | tr '\n' ' ' | tr -d '[:space:]'`"

    destination="$HOME/Documents/Android/APKs"
    mkdir -p "$destination"

    adb pull ${apk_path} ${destination}
    echo -e "\nAPK saved in \"$destination/$apk_name\""
}
  • Exemple :android_pull_apk com.android.contacts
  • Remarque : pour identifier le package:adb shell pm list packages

6

Comme indiqué ci-dessus, vous pouvez obtenir l'apk en utilisant la commande pull dans adb.

Depuis, vous parlez de vos applications installées, allez-y et regardez dans / data / app répertoire de votre système de fichiers Android. Vous y trouverez les fichiers APK.

Utilisez ensuite la commande adb - adb pull /data/data/appname.apk


6

Essayez cette commande one liner bash pour sauvegarder toutes vos applications:

for package in $(adb shell pm list packages -3 | tr -d '\r' | sed 's/package://g'); do apk=$(adb shell pm path $package | tr -d '\r' | sed 's/package://g'); echo "Pulling $apk"; adb pull -p $apk "$package".apk; done

Cette commande est dérivée du script de Firelord . Je viens de renommer toutes les apks en leurs noms de paquets pour résoudre le problème avec le script elcuco , c'est-à-dire le mêmebase.apk fichier écrasé sur Android 6.0 "Marshmallow" et au-dessus.

Notez que cette commande sauvegarde uniquement les applications tierces, car je ne vois pas l'intérêt de sauvegarder les applications intégrées. Mais si vous souhaitez également sauvegarder les applications système, omettez simplement l' -3option.


5

Si vous connaissez (ou si vous pouvez «deviner») le chemin vers le .apk(il semble être du format /data/app/com.example.someapp-{1,2,..}.apkvers, alors vous pouvez simplement le copier depuis/data/app également. Cela a fonctionné même sur mon téléphone Android stock non rooté.

Utilisez simplement une application Terminal Emulator (comme celle-ci ) et exécutez:

# step 1: confirm path
ls /data/app/com.example.someapp-1.apk
# if it doesn't show up, try -2, -3. Note that globbing (using *) doesn't work here.
# step 2: copy (make sure you adapt the path to match what you discovered above)
cp /data/app/com.example.someapp-1.apk /mnt/sdcard/

Ensuite, vous pouvez le déplacer de la carte SD à l'endroit où vous le souhaitez (ou le joindre à un e-mail, etc.). Le dernier morceau peut être techniquement facultatif, mais il vous facilite la vie lorsque vous essayez de faire quelque chose avec le .apkfichier.


5

Les procédures décrites ici ne fonctionnent pas pour Android 7 (Nougat) [et peut-être Android 6, mais je ne peux pas vérifier]. Vous ne pouvez pas extraire les fichiers .apk directement sous Nougat (sauf en mode root, mais cela nécessite un téléphone rooté). Mais, vous pouvez copier le fichier .apk vers un autre chemin (par exemple / sdcard / Download) sur le téléphone à l'aide du shell adb, puis vous pouvez effectuer une extraction adb à partir du chemin alternatif.


3
La réponse acceptée (y compris les adb shellcommandes du commentaire de @Isa A) a bien fonctionné pour moi sur Android 7.1.1, pas enracinée.
Jonathan Cottrill

4
  1. Ouvrez l'application dont vous souhaitez extraire l'apk sur votre téléphone.
  2. Obtenez l'application actuellement ouverte avec:

    adb shell dumpsys activity activities | grep mFocusedActivity
  3. Obtenez le chemin d'accès au nom du package

    adb shell pm path <packagename.apk>

4. Copiez le chemin d'accès que vous avez obtenu dans le répertoire sdcard

    adb shell cp /data/app/<packagename.apk> /sdcard

5.Tirez l'apk

    adb pull /sdcard/base.apk

Éditer

Si l'étape n ° 2 ne fonctionne pas, utilisez ceci:

adb shell dumpsys window windows | grep mCurrentFocus

3

Voici comment procéder:

Téléchargez et installez APK Extractor sur votre appareil. Il est gratuit et compatible avec presque tous les appareils Android. Un autre point positif est qu'il n'a même pas besoin de root ou quoi que ce soit pour fonctionner. Après l'avoir installé, lancez-le. Vous y verrez une liste des applications présentes sur votre appareil, qui incluent les applications que vous avez installées ultérieurement, ainsi que les applications système. Appuyez longuement sur n'importe quelle application que vous souhaitez extraire (vous pouvez sélectionner plusieurs ou toutes les applications à la fois), puis cliquez sur l'option d'extraction que vous voyez en haut. Vous aurez également la possibilité de partager via Bluetooth ou messagerie. Vous avez terminé, vous verrez les applications extraites comme AppName_AppPackage_AppVersionName_AppVersionCode.apk, qui seront enregistrées dans le chemin / sdcard / ExtrolvedApks / par défaut.

Pour une description détaillée de la façon d'extraire des fichiers apk dans Android , visitez: http://appslova.com/how-to-extract-apk-files-in-android/


3

Toutes ces réponses nécessitent plusieurs étapes pour chaque fichier apk récupéré de l'appareil. 1. déterminer le nom du package, 2. trouver le fichier et 3. le télécharger. J'ai construit un apk_grabberscript python simple pour le faire pour n'importe quelle application qui correspond à une expression régulière donnée, puis décompile ces apks dans des fichiers jar.


1

Je n'ai pas utilisé de code pour extraire le fichier .apk du mobile, mais j'ai utilisé un logiciel pour extraire le fichier .apk du mobile et les logiciels que j'ai utilisés sont ci-dessous avec le lien Google Play:

  1. Gestionnaire de fichiers ES File Explorer
  2. ASTRO Cloud & File Manager 3. Câble de données logiciel

J'espère que cela vous aide.


2
J'ai utilisé ES File Explorer. Je ne suis pas enraciné. Je suis juste allé dans Tools -> App Manager et j'ai appuyé longuement sur l'application pour laquelle je voulais l'APK. Cela a sélectionné l'application (et m'a permis d'en sélectionner d'autres). Je pense que j'ai appuyé sur le bouton Partager et j'ai pu m'envoyer l'APK (en utilisant Push Bullet, mais ce qui fonctionne pour vous).
schultzter

Si vous n'êtes pas pourri, vous pouvez essayer la sauvegarde et la restauration de l'application play.google.com/store/apps/details?id=mobi.infolife.appbackup
surhidamatya



1

j'ai un does not exist error

Voici comment je le fais fonctionner

adb shell pm list packages -f | findstr zalo
package:/data/app/com.zing.zalo-1/base.apk=com.zing.zalo

adb shell
mido:/ $ cp /data/app/com.zing.zalo-1/base.apk /sdcard/zalo.apk
mido:/ $ exit


adb pull /sdcard/zalo.apk Desktop

/sdcard/zalo.apk: 1 file pulled. 7.7 MB/s (41895394 bytes in 5.200s)

0

Encore un autre script bash (c'est-à-dire qui fonctionnera pour la plupart des systèmes basés sur Unix). Basé sur la réponse de Pedro Rodrigues , mais est légèrement plus facile à utiliser.

Améliorations par rapport à la version de Pedro:

  1. L'approche originale ne fonctionnait pas pour moi sur Android 7: adb pullcontinuait de se plaindre no such file or directorypendant que adb shellje pouvais accéder au fichier. J'ai donc utilisé une approche différente, avec un fichier temporaire.
  2. Lorsqu'il est lancé sans argument, mon script listera simplement tous les packages disponibles. Lorsqu'un nom de package partiel est fourni, il essaiera de deviner le nom complet du package. Il se plaindra s'il y a plusieurs extensions possibles.
  3. Je ne code pas le chemin de destination en dur; à la place, les fichiers APK sont enregistrés dans le répertoire de travail actuel.

Enregistrez-le dans un fichier exécutable:

#!/bin/bash
# Obtain APK file for given package from the device connected over ADB

if [ -z "$1" ]; then
    echo "Available packages: "
    adb shell pm list packages | sed 's/^package://'
    echo "You must pass a package to this function!"
    echo "Ex.: android_pull_apk \"com.android.contacts\""
    exit 1
fi

fullname=$(adb shell pm list packages | sed 's/^package://' | grep $1)
if [ -z "$fullname" ]; then
    echo "Could not find package matching $1"
    exit 1
fi
if [ $(echo "$fullname" | wc -l) -ne 1 ]; then
    echo "Too many packages matched:"
    echo "$fullname"
    exit 1
fi
echo "Will fetch APK for package $fullname"

apk_path="`adb shell pm path $fullname | sed -e 's/package://g' | tr '\n' ' ' | tr -d '[:space:]'`"
apk_name="`basename ${apk_path} | tr '\n' ' ' | tr -d '[:space:]'`"

destination="${fullname}.apk"

tmp=$(mktemp --dry-run --tmpdir=/sdcard --suffix=.apk)
adb shell cp "${apk_path}" "$tmp"
adb pull "$tmp" "$destination"
adb shell rm "$tmp"

[ $? -eq 0 ] && echo -e "\nAPK saved in \"$destination\""

0

Le plus simple est: Installez l'application "ShareIt" sur le téléphone. Installez maintenant l'application shareIt sur un PC ou un autre téléphone. À partir du téléphone, où l'application est installée, ouvrez ShareIt et envoyez. Sur un autre téléphone ou PC, ouvrez ShareIt et recevez.


0

J'ai vraiment aimé toutes ces réponses. La plupart des scripts à exporter et à renommer tous ont été écrits en Bash. J'ai fait un petit script Perl qui fait de même (qui devrait fonctionner à la fois en Perl pour Windows et Linux, uniquement testé sur Ubuntu).

download-apk.pl

#!/usr/bin/perl -w
# Automatically export all available installed APK's using adb
use strict;
print "Connect your device...\n";
system("adb", "wait-for-device");
open(my $OUT, '-|', 'adb', 'shell', 'pm', 'list', 'package', '-f');
my @list = split(/\s*/, `adb shell pm list packages -f`);
my $count = 0;
while(my $line = <$OUT>) {
        $line =~ s/^\s*|\s*$//g;
        my ($type, $path, $package) = $line =~ /^(.*?):(.*)=(.*)$/ ? ($1,$2,$3) : die('invalid line: '.$line);
        my $category = $path =~ /^\/(.*?)\// ? $1 : 'unknown';
        my $baseFile = $path =~ /\/([^\/]*)$/ ? $1 : die('Unknown basefile in path: '.$path);
        my $targetFile = "$category-$package.apk";
        print "$type $category $path $package $baseFile >> $targetFile\n";
        system("adb", "pull", $path);
        rename $baseFile, $targetFile;
}
  1. Assurez-vous que adb (.exe) se trouve dans votre chemin ou dans le même répertoire
  2. Connectez votre téléphone
  3. Exécutez download-apk.pl

La sortie est quelque chose de similaire à:

# ./download-apk.pl
Connect your device...
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
package system /system/app/YouTube/YouTube.apk com.google.android.youtube YouTube.apk >> system-com.google.android.youtube.apk
5054 KB/s (11149871 bytes in 2.154s)
package data /data/app/com.ghostsq.commander-1/base.apk com.ghostsq.commander base.apk >> data-com.ghostsq.commander.apk
3834 KB/s (1091570 bytes in 0.278s)
package data /data/app/de.blinkt.openvpn-2/base.apk de.blinkt.openvpn base.apk >> data-de.blinkt.openvpn.apk
5608 KB/s (16739178 bytes in 2.914s)
etc.

-1

Cela aidera quelqu'un qui recherche une réponse non technique

C'est un simple hack

Téléchargez l'application App Share/Send Prosur google play store. Sélectionnez l'application que vous souhaitez envoyer et la méthode d'envoi de l'application.

J'utilise généralement Bluetooth pour envoyer des applications à mon ordinateur ou à un autre téléphone.


Ce n'est pas facile à utiliser
APEXBoi
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.