"ให้คะแนนแอปนี้" - ลิงก์ในแอป Google Play สโตร์บนโทรศัพท์


266

ฉันต้องการใส่ "ให้คะแนนแอปนี้" ลิงก์ในแอป Android เพื่อเปิดรายการแอพในแอพ Google Play สโตร์ของผู้ใช้บนโทรศัพท์

  1. ฉันต้องเขียนโค้ดอะไรเพื่อสร้างmarket://หรือhttp://-link เปิดในแอป Google Play สโตร์บนโทรศัพท์
  2. คุณใส่รหัสที่ไหน
  3. ใครบ้างมีตัวอย่างการดำเนินการนี้
  4. คุณต้องระบุหน้าจอที่จะวางลิงค์market://หรือhttp://ลิงค์ไหนดีที่สุดในการใช้ - market://หรือhttp://?

สิ่งนี้มีทุกสิ่งที่คุณต้องการ: github.com/delight-im/AppRaterและคุณสามารถค้นหาซอร์สโค้ดเพื่อทำความเข้าใจว่ามันเสร็จสิ้นแล้ว
caw

คำตอบ:


555

ฉันเปิด Play Store จากแอพของฉันด้วยรหัสต่อไปนี้:

    Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
    Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
    // To count with Play market backstack, After pressing back button, 
    // to taken back to our application, we need to add following flags to intent. 
    goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
                    Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                    Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    try {
        startActivity(goToMarket);
    } catch (ActivityNotFoundException e) {
        startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("http://play.google.com/store/apps/details?id=" + context.getPackageName())));
    }

นี่จะเป็นการเปิด Play Store โดยที่หน้าแอพของคุณได้เปิดไปแล้ว ผู้ใช้สามารถให้คะแนนได้ที่นั่น


2
ฉันจะวางรหัสนี้ใน androidmanifest.xml ที่ไหน ฉันต้องเพิ่มอะไรอีกหรือไม่ สิ่งนั้นสอดคล้องกับลิงค์หรือปุ่มจริงบนหน้าจอที่ผู้ใช้กดอย่างไร ขอบคุณ
Adreno

1
คุณไม่จำเป็นต้องเพิ่มรหัสใด ๆ ในไฟล์ Manifest คุณเพียงแค่วางรหัสนี้ไว้ใน OnClickListener ของปุ่ม / ลิงก์ของคุณดังนั้นเมื่อคลิกปุ่มนี้รหัสจะถูกดำเนินการและ Play Store จะเปิดตัว
miguel.rodelas

61
การแก้ปัญหานี้ไม่นับรวมกับ Play market backstack หลังจากกดปุ่มย้อนกลับคุณจะไม่ถูกนำกลับไปที่แอปพลิเคชันของคุณ หากคุณต้องการให้เพิ่มบรรทัดนี้: intent.addFlags (Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
ม.ค. Muller

24
Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET: ค่าคงนี้ถูกคัดค้านในระดับ API 21 ในฐานะของ API 21 สิ่งนี้ดำเนินการเหมือนกันกับ FLAG_ACTIVITY_NEW_DOCUMENT ซึ่งควรใช้แทนสิ่งนี้
xnagyg

1
หากการโทรจากคลาส java ที่ไม่ใช่กิจกรรมคุณต้องผ่านบริบทเช่น context.startActivity (goTERT);
DMur

47

นี่คือรหัสที่ใช้งานได้และทันสมัย ​​:)

/*
* Start with rating the app
* Determine if the Play Store is installed on the device
*
* */
public void rateApp()
{
    try
    {
        Intent rateIntent = rateIntentForUrl("market://details");
        startActivity(rateIntent);
    }
    catch (ActivityNotFoundException e)
    {
        Intent rateIntent = rateIntentForUrl("https://play.google.com/store/apps/details");
        startActivity(rateIntent);
    }
}

private Intent rateIntentForUrl(String url)
{
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s?id=%s", url, getPackageName())));
    int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
    if (Build.VERSION.SDK_INT >= 21)
    {
        flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
    }
    else
    {
        //noinspection deprecation
        flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
    }
    intent.addFlags(flags);
    return intent;
}

ใส่รหัสในสิ่งที่Activityคุณต้องการโทรจาก
เมื่อผู้ใช้คลิกปุ่มเพื่อให้คะแนนแอปเพียงเรียกใช้rateApp()ฟังก์ชัน


อะไร NuGet แพคเกจฉันควรเพิ่มและสิ่ง namespace ฉันควรจะเป็นusingสำหรับการIntentที่จะเป็นประเภททำงานได้? ฉันพบAndroid.Contentแต่ฉันขาดทุนด้วยIntentในแบบฟอร์ม Xamarin
s3c

24

ฉันใช้รหัสนี้เสมอ:

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=PackageName")));

4
ชอบหนึ่ง liners เสมอ :)
androidStud

ฉันใช้มัน แต่มันแสดงข้อผิดพลาดนี้ - `android.content.ActivityNotFoundException: ไม่พบกิจกรรมใดที่จัดการ Intent {act = android.intent.action.VIEW dat = ตลาด: // รายละเอียด id = PackageName}` - ฉันจะทำอะไรได้บ้าง ?
Mina Dahesh

คุณตรวจสอบสิ่งนี้ได้ไหม
Cabezas

@Cabezas ฉันต้องการแสดงตลาดที่มีอยู่ทั้งหมดทางโทรศัพท์ ด้วยการคลิกที่พวกเขาถ้าแอปของฉันมีอยู่ตลาดจะแสดงแอพ ดังนั้นฉันควรทำอย่างไร
Mina Dahesh

1
@Cabezas ฉันใช้รหัสนี้: `ลอง {เจตนาเจตนา = เจตนาใหม่ (Intent.ACTION_VIEW) intent.setData (Uri.parse ( "ตลาดสด: // รายละเอียด id = vow_note.maxsoft.com.vownote?")); intent.setData (Uri.parse ( "myket: // คิดเห็น id = vow_note.maxsoft.com.vownote")); startActivity (เจตนา); } catch (ActivityNotFoundException e1) {ลอง {startActivity (Intent ใหม่ (Intent.ACTION_VIEW, Uri.parse ("URL ของตลาด"))); startActivity (เจตนาใหม่ (Intent.ACTION_VIEW, Uri.parse ("URL ของตลาด"))); } catch (ActivityNotFoundException e2) {Toast.} `
Mina Dahesh

18

นี่คือถ้าคุณเผยแพร่แอปของคุณใน Google Play Store และ Amazon Appstore ฉันจัดการกรณีที่ผู้ใช้ (โดยเฉพาะในจีน) ไม่มีทั้ง app store และเบราว์เซอร์

public void goToMyApp(boolean googlePlay) {//true if Google Play, false if Amazone Store
    try {
       startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse((googlePlay ? "market://details?id=" : "amzn://apps/android?p=") +getPackageName())));
    } catch (ActivityNotFoundException e1) {
        try {
            startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse((googlePlay ? "http://play.google.com/store/apps/details?id=" : "http://www.amazon.com/gp/mas/dl/android?p=") +getPackageName())));
        } catch (ActivityNotFoundException e2) {
            Toast.makeText(this, "You don't have any app that can open this link", Toast.LENGTH_SHORT).show();
        }
    }
}

ไม่ตอบคำถามในมือ

รหัสเกี่ยวกับการเปิดรายชื่อร้านค้าแอป Amazon ของแอพของคุณ?
isJulian00

อะไร NuGet แพคเกจฉันควรเพิ่มและสิ่ง namespace ฉันควรจะเป็นusingสำหรับการIntentที่จะเป็นประเภททำงานได้? ฉันพบAndroid.Contentแต่ฉันขาดทุนด้วยIntentในแบบฟอร์ม Xamarin
s3c

10

คุณสามารถเรียกใช้getInstalledPackages ()จากคลาสPackageManagerและตรวจสอบเพื่อให้แน่ใจว่าติดตั้งคลาสตลาดแล้ว นอกจากนี้คุณยังสามารถใช้queryIntentActivities ()เพื่อให้แน่ใจว่าเจตนาที่คุณสร้างจะสามารถจัดการได้โดยบางสิ่งแม้ว่าจะไม่ใช่แอปพลิเคชันการตลาดก็ตาม นี่อาจเป็นสิ่งที่ดีที่สุดที่จะทำจริงเพราะมีความยืดหยุ่นและแข็งแกร่งที่สุด

คุณสามารถตรวจสอบว่ามีแอพตลาดหรือไม่

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse("market://search?q=foo"));
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);

หากรายการมีอย่างน้อยหนึ่งรายการตลาดจะอยู่ที่นั่น

คุณสามารถใช้สิ่งต่อไปนี้เพื่อเปิด Android Market บนหน้าแอปพลิเคชันของคุณซึ่งเป็นระบบอัตโนมัติมากขึ้น:

Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("market://details?id=" + getPackageName()));
startActivity(i);

หากคุณต้องการทดสอบสิ่งนี้บนเครื่องจำลองของคุณคุณอาจไม่ได้ติดตั้งในตลาด: ดูลิงค์เหล่านี้สำหรับรายละเอียดเพิ่มเติม:

วิธีเปิดใช้งาน Android Market ใน Google Android Emulator

การติดตั้ง Google Play บน Android Emulator


ฉันจะวางรหัสนี้ใน androidmanifest.xml ที่ไหน ฉันต้องเพิ่มอะไรอีกหรือไม่ สิ่งนั้นสอดคล้องกับลิงค์หรือปุ่มจริงบนหน้าจอที่ผู้ใช้กดอย่างไร ขอบคุณ
Adreno

8

ฉันใช้วิธีการนี้เพื่อให้คะแนนผู้ใช้แอปของฉัน:

public static void showRateDialog(final Context context) {
    AlertDialog.Builder builder = new AlertDialog.Builder(context)
            .setTitle("Rate application")
            .setMessage("Please, rate the app at PlayMarket")
            .setPositiveButton("RATE", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (context != null) {
                        String link = "market://details?id=";
                        try {
                            // play market available
                            context.getPackageManager()
                                    .getPackageInfo("com.android.vending", 0);
                        // not available
                        } catch (PackageManager.NameNotFoundException e) {
                            e.printStackTrace();
                            // should use browser
                            link = "https://play.google.com/store/apps/details?id=";
                        }
                        // starts external action
                        context.startActivity(new Intent(Intent.ACTION_VIEW, 
                                Uri.parse(link + context.getPackageName())));
                    }
                }
            })
            .setNegativeButton("CANCEL", null);
    builder.show();
}

มีไว้เพื่ออะไร - market://details?id=ลิงก์แอปของฉันเป็นเหมือนhttps:\\play.google.com\apps\details?id=
Sagar Balyan

2
@SagarBalyan มันเป็น uri พิเศษสำหรับการเปิดหน้าแอปของคุณที่แอปพลิเคชันตลาด Google Play หากคุณเริ่มต้นกิจกรรมด้วยลิงก์ที่คุณให้กับ Android จะเปิดหน้าแอปของคุณในเบราว์เซอร์เริ่มต้นหรือจะให้คุณเลือกว่าจะเริ่มแอปเบราว์เซอร์ใด
gtgray

5

รุ่น kotlin

fun openAppInPlayStore() {
    val uri = Uri.parse("market://details?id=" + context.packageName)
    val goToMarketIntent = Intent(Intent.ACTION_VIEW, uri)

    var flags = Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_MULTIPLE_TASK
    flags = if (Build.VERSION.SDK_INT >= 21) {
        flags or Intent.FLAG_ACTIVITY_NEW_DOCUMENT
    } else {
        flags or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    goToMarketIntent.addFlags(flags)

    try {
        startActivity(context, goToMarketIntent, null)
    } catch (e: ActivityNotFoundException) {
        val intent = Intent(Intent.ACTION_VIEW,
                Uri.parse("http://play.google.com/store/apps/details?id=" + context.packageName))

        startActivity(context, intent, null)
    }
}

4

คุณสามารถใช้มันได้ผลกับฉัน

public static void showRateDialogForRate(final Context context) {
    AlertDialog.Builder builder = new AlertDialog.Builder(context)
            .setTitle("Rate application")
            .setMessage("Please, rate the app at PlayMarket")
            .setPositiveButton("RATE", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (context != null) {
                        ////////////////////////////////
                        Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
                        Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
                        // To count with Play market backstack, After pressing back button,
                        // to taken back to our application, we need to add following flags to intent.
                        goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
                                Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET |
                                Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
                        try {
                            context.startActivity(goToMarket);
                        } catch (ActivityNotFoundException e) {
                            context.startActivity(new Intent(Intent.ACTION_VIEW,
                                    Uri.parse("http://play.google.com/store/apps/details?id=" + context.getPackageName())));
                        }


                    }
                }
            })
            .setNegativeButton("CANCEL", null);
    builder.show();
}

4

เล่นคะแนนร้านค้า

 btn_rate_us.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri.parse("market://details?id=" + getPackageName());
                Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
                // To count with Play market backstack, After pressing back button,
                // to taken back to our application, we need to add following flags to intent.
                goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
                        Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
                        Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
                try {
                    startActivity(goToMarket);
                } catch (ActivityNotFoundException e) {
                    startActivity(new Intent(Intent.ACTION_VIEW,
                            Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));
                }
            }
        });

3

อีกวิธีหนึ่งที่อาจใช้งานได้สำหรับคุณคือ Linkify หากฉันมี TextView ที่ขอให้ผู้ใช้ให้คะแนนแอปนี้ฉันสามารถลิงก์สองสามคำในข้อความเพื่อไฮไลต์และเมื่อผู้ใช้สัมผัสกับพวกเขา Play store จะเปิดขึ้นพร้อมสำหรับการตรวจสอบ:

class playTransformFilter implements TransformFilter {
   public String transformUrl(Matcher match, String url) {
        return "market://details?id=com.qwertyasd.yourapp";
   }
}

class playMatchFilter implements MatchFilter {
    public boolean acceptMatch(CharSequence s, int start, int end) {
        return true;
    }
}
text1 = (TextView) findViewById(R.id.text1);
text1.setText("Please rate it.");
final Pattern playMatcher = Pattern.compile("rate it");
Linkify.addLinks(text1, playMatcher, "", 
                   new playMatchFilter(), new playTransformFilter());

3

จุดที่เกี่ยวกับคำตอบทั้งหมดที่มีการติดตั้งใช้งานตามกลยุทธ์ getPackageName () คือการใช้ BuildConfig.APPLICATION_ID อาจจะตรงไปตรงมามากขึ้นและทำงานได้ดีถ้าคุณใช้ฐานรหัสเดียวกันเพื่อสร้างแอปหลายแอปที่มีรหัสแอปที่แตกต่างกัน ผลิตภัณฑ์ป้ายขาว)


2
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.StringRes;
import android.widget.Toast;

public class PlayStoreLink {

public void checkForUpdate(Context context, int applicationId) 
{
    try {
        context.startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse(context.getString(R.string.url_market_details)
                        + applicationId)));
    } catch (android.content.ActivityNotFoundException anfe) {
        try {
            context.startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse(context.getString(R.string.url_playstore_app)
                            + applicationId)));
        } catch (Exception e) {
            Toast.makeText(context,
                    R.string.install_google_play_store,
                    Toast.LENGTH_SHORT).show();
        }
    }
}

public void moreApps(Context context, @StringRes int devName) {
    try {
        context.startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse(context.getString(R.string.url_market_search_app)
                        + context.getString(devName))));
    } catch (android.content.ActivityNotFoundException anfe) {
        try {
            context.startActivity(new Intent(Intent.ACTION_VIEW,
                    Uri.parse(context.getString(R.string.url_playstore_search_app)
                            + context.getString(devName))));
        } catch (Exception e) {
            Toast.makeText(context,
                    R.string.install_google_play_store,
                    Toast.LENGTH_SHORT).show();
        }
    }
}

public void rateApp(Context context, int applicationId) {
    try {
        Uri uri = Uri.parse(context.getString(R.string.url_market_details)
                + applicationId);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        int flags = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH)
            flags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
        else
            flags |= Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
        intent.addFlags(flags);
        context.startActivity(intent);
    } catch (ActivityNotFoundException e) {
        checkForUpdate(context, applicationId);
    }
}
}

<string name="install_google_play_store" translatable="false">Please install google play store and then try again.</string>
<string name="url_market_details" translatable="false">market://details?id=</string>
<string name="url_playstore_app" translatable="false">https://play.google.com/store/apps/details?id=</string>
<string name="url_market_search_app" translatable="false">market://search?q=pub:</string>
<string name="url_playstore_search_app" translatable="false">http://play.google.com/store/search?q=pub:</string>
<string name="app_link" translatable="false">https://play.google.com/store/apps/details?id=</string>

devName เป็นชื่อบัญชีนักพัฒนาซอฟต์แวร์ใน Play Store


2

คุณสามารถใช้รหัสง่ายๆนี้เพื่อให้คะแนนแอปของคุณในกิจกรรมของคุณ

try {
    Uri uri = Uri.parse("market://details?id=" + getPackageName());
    Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
    startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
    startActivity(new Intent(Intent.ACTION_VIEW,
    Uri.parse("http://play.google.com/store/apps/details?id=" + getPackageName())));
}

มีไว้เพื่ออะไร - market://details?id=ลิงก์แอปของฉันเป็นเหมือนhttps:\\play.google.com\apps\details?id=
Sagar Balyan

@SagarBalyan หากผู้ใช้มีหลายแอพตลาดมันจะเปิดร้านค้าเริ่มต้นหรือแสดงเจตนาให้ทุกร้านค้าที่มีอยู่
Avi Parshan

2

ผมใช้วิธีการต่อไปนี้โดยการรวมนี้และนี้คำตอบได้โดยไม่ต้องใช้การเขียนโปรแกรมตามข้อยกเว้นและยังสนับสนุนก่อน API 21 ธงเจตนา

@SuppressWarnings("deprecation")
private Intent getRateIntent()
{
  String url        = isMarketAppInstalled() ? "market://details" : "https://play.google.com/store/apps/details";
  Intent rateIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(String.format("%s?id=%s", url, getPackageName())));
  int intentFlags   = Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
  intentFlags      |= Build.VERSION.SDK_INT >= 21 ? Intent.FLAG_ACTIVITY_NEW_DOCUMENT : Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
  rateIntent.addFlags(intentFlags);
  return rateIntent;
}

private boolean isMarketAppInstalled()
{
  Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=anyText"));
  return getPackageManager().queryIntentActivities(marketIntent, 0).size() > 0;
}


// use
startActivity(getRateIntent());

เนื่องจากการตั้งค่าสถานะเจตนาFLAG_ACTIVITY_CLEAR_WHEN_TASK_RESETเลิกใช้จาก API 21 ฉันใช้@SuppressWarnings("deprecation")แท็กในวิธี getRateIntent เนื่องจาก SDK เป้าหมายของแอปของฉันต่ำกว่า API 21


ฉันยังลองใช้วิธีการอย่างเป็นทางการ ของ Google ที่แนะนำบนเว็บไซต์ของพวกเขา (6 ธันวาคม 2019) สิ่งที่ฉันเห็นมันไม่ได้จัดการกับเคสหากไม่ได้ติดตั้งแอพ Play Store

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(
    "https://play.google.com/store/apps/details?id=com.example.android"));
intent.setPackage("com.android.vending");
startActivity(intent);

0

ประกาศเมธอดในคลาสกิจกรรมของคุณ จากนั้นคัดลอกและวางรหัสด้านล่าง

private void OpenAppInPlayStore(){

    Uri uri = Uri.parse("market://details?id=" + this.getPackageName());
    Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
    // To count with Play market backstack, After pressing back button,
    // to taken back to our application, we need to add following flags to intent.
    goToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
            Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
            Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
    try {
        startActivity(goToMarket);
    } catch (ActivityNotFoundException e) {
        startActivity(new Intent(Intent.ACTION_VIEW,
                Uri.parse("http://play.google.com/store/apps/details?id=" + this.getPackageName())));
    }

}

ตอนนี้เรียกวิธีการนี้จากที่ใดก็ได้ของรหัสของคุณ

ติดตามภาพด้านล่างจากโครงงานที่ใช้งานจริงของฉัน

ป้อนคำอธิบายรูปภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.