有什么方法可以查看Chrome浏览器的通知历史记录?


55

我从多个网站收到Chrome通知,当我什至没有为这些网站打开任何标签时,它们就会起作用。

但是有时当我不在办公桌旁或看着笔记本电脑时,会收到这些Chrome通知。

由于其中一些通知对我有用,因此我希望能够访问任何我错过的内容。

有没有办法查看通知历史记录?


1
看起来不像。看着这篇文章(theverge.com/2015/10/14/9531133/…),他们重新排列了通知策略,并将其从桌面上删除以放置在各个网页上。访问新通知的唯一方法是单击Google页面上的铃声。
特里


我找到通知列表的唯一地方是触发他们的网站是否通过他们的网站收到了通知。Chrome似乎没有以类似的方式收集它们,chrome://notifications并且它们也没有进入操作系统。
杰森·莱顿

接受有效答案@paradroid
Satheesh

Answers:


31

如果您使用的是Mac,那就有办法了!😄

通知列表如下所示:

通知列表如下所示。

您所需要做的就是:

1.在Chrome浏览器中,转到:

chrome://flags/

2.寻找:

Enable native notifications. Mac

3.启用它,重新启动chrome,就完成了。请享用!

编辑:

  • 您可能不再需要执行上述操作。

从Chrome 59开始,通过Notifications API或chrome.notifications扩展API发送的通知将直接由macOS本机通知系统显示,而不是由Chrome本身的系统显示。[ 来源 ]


2
这并没有回答查看通知历史的问题,而只是查看通知。
比约恩

6
@BjornTipling它确实回答了。他问他是否可以看到他不在时错过的通知,而我的方法正是这样做的。
Esdras Lopez

1
如果您将链接作为注释,我将为您将它们添加到您的帖子中,@ EsdrasLopez
user418150 '18

1
@ user418150我对此表示赞赏,但现在我已享有声誉。:)检查编辑。
Esdras Lopez '18

2
这里的主要问题是,仅当您单击通知时,它才会存储通知。我多次单击一个有趣的文章标题,只是使其无法加载,但是仍然将其从通知列表中删除。通常情况下,文章太新而不能被Google搜索,并且通知标题常常与文章标题不匹配,因此它会丢失在网络的肠子中。
iBorg

11

在MacOSX上,您将在“库/应用程序支持”中找到Chrome目录。打开终端应用程序并运行以下命令:

cd ~/Library/Application\ Support/Google/Chrome/Default/Platform\ Notifications/
ls -la

现在您将看到如下文件:

drwx------@  7 visi  staff   224 Jul 13 18:16 .
drwx------  75 visi  staff  2400 Jul 15 11:05 ..
-rw-------@  1 visi  staff   759 Jul 15 10:57 000003.log
-rw-------@  1 visi  staff    16 Jul 13 18:16 CURRENT
-rw-------@  1 visi  staff     0 Jul 13 18:16 LOCK
-rw-------@  1 visi  staff   147 Jul 13 18:16 LOG
-rw-------@  1 visi  staff    41 Jul 13 18:16 MANIFEST-000001

您可以看到最新的是000003.log,因此请使用下一条命令进行检查:

tail -n 100 000003.log

您将在此日志中看到最后100个项目。然后,您可以打开Chrome设置并禁用该网站通知。

请注意,如果您在Chrome中有多个配置文件,则您的路径可以不同,如下所示(Profile1而非Default):

cd ~/Library/Application\ Support/Google/Chrome/Profile\ 1/Platform\ Notifications/

3
这应该是公认的答案。:)
Cody A. Ray

1
仍在2019年工作(尽管日志需要一些解释)。伟大的答案,谢谢
carpii

11

如果转到%LocalAppData%\Google\Chrome\User Data\Default\Platform Notifications,则将有一个过去通知的日志文件。


4
很好,但请考虑将路径指定为“%LocalAppData%\ Google \ Chrome \ User Data \ Default \ Platform Notifications”,而不是硬编码。它可以在任何PC上完美运行。
德米特里·古萨罗夫

在UserData /文件夹中,您可能必须先找到配置文件文件夹,例如“ C:\ Users \ username \ AppData \ Local \ Google \ Chrome \ UserData \ Profile 1 \ Platform Notifications”
Maffelu

1
该数据是二进制的。怎么看?
盖亚

在Chrome 71上,日志文件为空。这在某个时候被禁用吗?
詹姆士

2
@Gaia我也想知道同样的事情,只是提出了一些糟糕的Java代码,这些代码在解密大多数代码方面做得很好。我将其张贴在下面:superuser.com/a/1410742/778383
Dreamspace总裁

3

由于似乎无法直接获得通知的记录,因此,如果我遇到相同的问题,我会以推荐使用Pushbullet的用户的身份使用Android手机仿真器或电话来作弊。但是不仅有Pushbullet,还有很多其他应用程序,我们可以在一个单独的线程中讨论android技巧来侦听和记录通知。

如果您是一名程序员,则可以通过自制扩展程序解决问题:

https://stackoverflow.com/questions/15949606/how-can-i-listen-to-notifications

“您可以挂钩webkitNotifications.createNotification函数,以便无论何时创建通知,您都将运行一些特定的代码。”


2

您可以查看“推送通知”的历史记录。在任务栏PC屏幕的右下角,看起来像一个气泡,如果将鼠标悬停在它上面,您将看到它实际上称为“通知”。如果单击该气泡,它将显示您的未读/新电子邮件以及尚未关闭的所有推送通知。我来到这里寻找答案,但没有找到答案,但是设法解决了。我正在使用Windows 10。


是的,这是Win10上的最新消息,但这是Windows的最终答案。
paradroid

1

触摸上面提到的内容,但要确保您不会错过OSX上的通知:

  1. 在主顶部栏的右侧,单击通知图标。

  2. 单击齿轮(通知显示的右下角)

  3. 选择Chrome以设置通知的显示方式。

  4. 默认情况下,“横幅”被选中,它们会自动消失。而是选择“警报”类型,只要您不确认它们,它们就会一直保留在那里!

别客气 :)


-1

似乎Pushbullet可以解决您的问题。他们声称您可以使用其Chrome扩展程序看到错过的通知。

https://blog.pushbullet.com/2014/10/23/easily-access-your-recent-notifications-in-chrome/


请阅读“ 如何推荐软件”以获取最少的必需信息,以及有关如何在“超级用户”上推荐软件的建议。为了使您的答案有用,即使提供的链接中断,也应将这些详细信息编辑为您的答案。
我说恢复莫妮卡

嘿,很好。我会尝试的。我实际上已经在使用Pushbullet,但是没有意识到这个Chrome扩展程序。
paradroid

似乎找不到此功能。弹出通知,并且在通知的历史记录中没有任何痕迹。
madprops

我重新考虑了这个问题,关键是这个。如果您的手机收到通知,pushbullet会将其发送到您的桌面,并告知您可能有未读的通知(您可能已经在手机上看到了或有什么东西)。您在哪些网站上收到Chrome通知?如果有适用的应用程序,则可以随时安装它,然后将通知从pushbullet发送到台式机/笔记本电脑/其他任何设备。
Socialorganix Contentbrandmgmt

1
Pushbullet中的“通知”功能仅用于在台式机上查看来自Android手机的通知,如果您使用的是Mac台式机,则与iPhone相同。它与Chrome通知无关。
波阿斯

-1

多亏了Corey的上述回答,以及一个懒惰的星期六,我手忙脚乱,现在我可以在IDE的控制台中看到最近的Chrome通知列表,甚至可以单击URL。

由于我不了解解释二进制数据的正确方法,因此代码很糟糕,并使用了粗略的启发式方法。

但它是一吨比没有好。输出示例(节选):

https://www.finanzen.net/nachricht/aktien/kw-9-tops-und-flops-der-tecdax-aktien-in-der-vergangenen-woche-7195100
https://images.finanzen.net/mediacenter/unsortiert/TecDAX_boerse_frankfurt0016_kl.jpg
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.*
KW 9: Tops und Flops der TecDAX-Aktien in der vergangenen Woche
So bewegten sich die Einzelwerte des TecDAX in der zurückliegenden Handelswoche.
HideOnTheseRoutes
Home/Index;Article/News/Index
tag-7195100
NotificationIdentifier
1061622960{


https://www.youtube.com/watch?v=W-mlD_bYKdU&feature=push-u-sub&attr_tag=0SL8UpnrTOnTECxr%3A6
https://lh5.googleusercontent.com/-raJM5SITO34/AAAAAAAAAAI/AAAAAAAAAAA/UtLljlL4Wpc/s96-c-mo/photo.jpg
New from Market Moves
Trade Recap: $1,500 in PROFITS*˜
COuAyJGY4uACEAY=
attributionTag
0SL8UpnrTOnTECxr:6{
 from Market MovesTrade Recap: $1,500 in PROFITS

值得钉十字架的Java代码:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;




/**
 * v[1, 2019-03-02 13:00 UTC]
 *
 * by dreamspace-president.com
 */
final public class CrappyChromeNotificationHistoryReader {


    public static void main(final String[] args) {

        final File file = new File(
                "C:\\Users\\[YOUR_NAME_HERE]\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Platform Notifications\\000003.log");

        final List<ChromeNotificationStuff> notifications = obtainChromeNotificationStuff(file);
        for (ChromeNotificationStuff notification : notifications) {
            System.err.println();
            System.err.println(notification);
        }
        System.exit(0);
    }


    public static List<ChromeNotificationStuff> obtainChromeNotificationStuff(final File file) {

        final List<ChromeNotificationStuff> ret = new ArrayList<>();

        final List<DumbTokenList> listOfDumbTokenLists = doTheInsaneParsingThing(file);
        int instanceCounter = 0;
        for (DumbTokenList dtl : listOfDumbTokenLists) {

            final List<String> urls = new ArrayList<>();
            final List<String> texts = new ArrayList<>();

            for (String token : dtl.tokens) {
                if (token.startsWith("https://") || token.startsWith("http://")) {
                    urls.add(token);
                } else {
                    texts.add(token);
                }
            }


            // Remove unimportant URLs.
            for (int i = urls.size() - 1; i > 0; i--) {
                final String urlThis = urls.get(i);
                final int lenThis = urlThis.length();
                for (int ii = i - 1; ii >= 0; ii--) {
                    final String urlThat = urls.get(ii);
                    final int lenThat = urlThat.length();

                    if (lenThis > lenThat) {
                        if (urlThis.startsWith(urlThat)) {
                            final String removed = urls.remove(ii);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThis); // because was better or equal
                            break;
                        }
                    } else {
                        if (urlThat.startsWith(urlThis)) {
                            final String removed = urls.remove(i);
                            //                            System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + urlThat); // because was better or equal
                            break;
                        }
                    }

                }
            }

            ret.add(new ChromeNotificationStuff(instanceCounter, urls, texts));
            instanceCounter++;
        }

        ret.sort(null);

        return ret;
    }


    final public static class ChromeNotificationStuff implements Comparable<ChromeNotificationStuff> {


        private final int instanceCounter;
        final public List<String> urls;
        final public List<String> texts;


        private ChromeNotificationStuff(final int instanceCounter,
                                        final List<String> urls,
                                        final List<String> texts) {

            this.instanceCounter = instanceCounter;

            this.urls = Collections.unmodifiableList(urls);
            this.texts = Collections.unmodifiableList(texts);
        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String url : urls) {
                sb.append(url).append('\n');
            }
            for (String text : texts) {
                sb.append(text).append('\n');
            }
            return sb.toString();
        }


        @Override
        public int compareTo(final ChromeNotificationStuff o) { // Newest (= last) notifications first, please.

            return Integer.compare(o.instanceCounter, instanceCounter);
        }
    }




    final private static double MIN_LENGTH_DIFFERENCE_RATIO = 0.7;//0.9;
    final private static double MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES = 0.2;




    final private static class DumbTokenList {


        final private static int MIN_LENGTH = 10; //6;
        final private static String[] EXTENSIONS = new String[] { ".jpg", ".jpeg", ".png", ".gif", ".html", ".htm", ".php" };
        final private static int MAX_EXTRA_CRAP_AFTER_EXTENSIONS = 3;
        final private static String SAFE_URL_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;="; // https://stackoverflow.com/a/1547940/3500521

        final private String originalText;
        final private List<String> tokens;


        private DumbTokenList(final String textWithBinaryCrap) {

            originalText = textWithBinaryCrap;

            final List<String> tokens = new ArrayList<>();

            final Consumer<String> addTokenButTryToDecrappifyExtensionsFirstAnTing = token -> {


                if (token.startsWith("ttps://") || token.startsWith("ttp://")) {
                    token = "h" + token;
                }


                final List<String> newTokens = new ArrayList<>();

                if (token.startsWith("http")) {
                    final int tokenLength = token.length();
                    boolean found = false;
                    for (int i = 0; i < tokenLength; i++) {
                        final char c = token.charAt(i);
                        if (SAFE_URL_CHARACTERS.indexOf(c) < 0) {
                            newTokens.add(token.substring(0, i));
                            newTokens.add(token.substring(i));
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        newTokens.add(token);
                    }
                } else {
                    newTokens.add(token);
                }

                for (String newToken : newTokens) {


                    String foundExt = null;
                    int foundExtLen = 0;
                    int foundExtAt = -1;
                    for (String extension : EXTENSIONS) {
                        final int idx = newToken.indexOf(extension);
                        if (idx >= 0) {
                            final int extLen = extension.length();
                            if (idx > foundExtAt || (idx == foundExtAt && extLen > foundExtLen)) {
                                foundExt = extension;
                                foundExtLen = extLen;
                                foundExtAt = idx;
                            }
                        }
                    }
                    if (foundExt != null) {
                        final int amountOfCharactersAfterThisFind = newToken.length() - foundExtAt - foundExtLen;
                        if (amountOfCharactersAfterThisFind <= MAX_EXTRA_CRAP_AFTER_EXTENSIONS) {
                            // OK. Shorten this bitch.
                            newToken = newToken.substring(0, foundExtAt + foundExtLen);
                        }
                    }


                    if (newToken.startsWith("http")) {
                        if (!newToken.startsWith("http://") && !newToken.startsWith("https://")) {
                            continue;
                        }
                    }


                    if (newToken.startsWith("/watch?v=")) {
                        newToken = "https://www.youtube.com" + newToken;
                    }


                    if (newToken.length() >= MIN_LENGTH) {
                        tokens.add(newToken);
                    }


                }

            };

            final StringBuilder sb = new StringBuilder();

            final int len = textWithBinaryCrap.length();
            for (int i = 0; i <= len + 1; i++) {

                final char c = i < len ? textWithBinaryCrap.charAt(i) : 0;

                if (c < ' ' || c == '"') {

                    String potentialText = sb.toString();
                    while (true) {
                        final int httpIDX = potentialText.indexOf("http", 1);
                        if (httpIDX < 0) {
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(potentialText);
                            break;
                        } else {
                            final String snippet = potentialText.substring(0, httpIDX);
                            potentialText = potentialText.substring(httpIDX);
                            addTokenButTryToDecrappifyExtensionsFirstAnTing.accept(snippet);
                        }
                    }

                    sb.setLength(0);

                    if (c == '"') {
                        // Skip this and the next. (thus "i < len +1")
                        i++;
                    }
                } else {
                    sb.append(c);
                }
            }


            // Remove quasi-duplicates. Sue me.
            //            System.err.println("\n*** STARTING DEDUPLICATION ***");
            final int lSize = tokens.size();
            for (int i = lSize - 1; i > 0; i--) { // (not 0 itself, wouldn't make sense)

                if (i < tokens.size()) {

                    final String entry = tokens.get(i);

                    for (int ii = i - 1; ii >= 0; ii--) { // (incl. 0)

                        final String otherEntry = tokens.get(ii);

                        final Boolean removeNoneOrFirstOrSecond = areLinesTooSimilar(entry, otherEntry);
                        if (removeNoneOrFirstOrSecond != null) {

                            if (!removeNoneOrFirstOrSecond) {
                                final String removed = tokens.remove(i);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + otherEntry); // because was better or equal
                            } else {
                                final String removed = tokens.remove(ii);
                                //                                System.err.println("\nREMOVED: " + removed + "\nKEPT   : " + entry); // because was better or equal
                            }
                            break; // IMPORTANT!
                        }

                    }
                }
            }


            this.tokens = Collections.unmodifiableList(tokens);

        }


        public String toString() {

            final StringBuilder sb = new StringBuilder();
            for (String token : tokens) {
                sb.append(token).append('\n');
            }
            return sb.toString();
        }


    }


    /**
     * Do NOT call with NULL/EMPTY arguments.
     *
     * @return NULL if not too similar. False if the FIRST seems superfluous. True if the SECOND seems superfluous.
     */
    private static Boolean areLinesTooSimilar(final String line1,
                                              final String line2) {

        final int l1 = line1.length();
        final int l2 = line2.length();

        final double lenDiffRatio = Math.min(l1, l2) / (double) Math.max(l1, l2); // Results in 1 or less.

        if (lenDiffRatio >= MIN_LENGTH_DIFFERENCE_RATIO) {

            if (l2 < l1) {
                // Compare the other way round.
                if (line1.contains(line2)) {
                    return false;
                }
            } else {
                if (line2.contains(line1)) {
                    return true;
                }
            }

        }

        return null;
    }


    private static List<DumbTokenList> doTheInsaneParsingThing(final File file) {

        final List<DumbTokenList> ret = new ArrayList<>();

        final StringBuilder sb = new StringBuilder();
        try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {

            final int bufMinus1 = 4;
            final Charset charset = Charset.forName("Cp1252"); // =ansi

            final int[] buf = new int[bufMinus1 + 1]; // "DATA"
            //            while ((buf[buf.length - 1] = is.read()) >= 0) {
            while (true) {

                buf[bufMinus1] = is.read();

                if (buf[bufMinus1] < 0 || (
                        buf[0] == 'D' &&
                                buf[1] == 'A' &&
                                buf[2] == 'T' &&
                                buf[3] == 'A' &&
                                buf[4] == ':')) {

                    if (sb.length() > 0) {
                        ret.add(new DumbTokenList(sb.toString()));
                        sb.setLength(0);
                    }

                    if (buf[bufMinus1] < 0) {
                        break;
                    }

                } else {

                    sb.append(new String(new byte[] { (byte) buf[bufMinus1] }, charset));
                    //                    sb.append((char) buf[bufMinus1]);
                }


                // Shift minibuffer to front.
                for (int i = 0; i < bufMinus1; i++) {
                    buf[i] = buf[i + 1];
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }


        // DEDUPLICATE DTLs
        for (int i = ret.size() - 1; i > 0; i--) {

            if (i < ret.size()) {
                final DumbTokenList dtlThis = ret.get(i);
                final int dtlThisTokenCount = dtlThis.tokens.size();

                for (int ii = i - 1; ii >= 0; ii--) {
                    final DumbTokenList dtlThat = ret.get(ii);
                    final int dtlThatTokenCount = dtlThat.tokens.size();


                    int scoreViaRemainingLines_this = dtlThisTokenCount;
                    int scoreViaRemainingLines_that = dtlThatTokenCount;


                    for (int o = 0; o < dtlThisTokenCount; o++) {
                        final String tokenThis = dtlThis.tokens.get(o);
                        for (int oo = 0; oo < dtlThatTokenCount; oo++) {
                            final String tokenThat = dtlThat.tokens.get(oo);

                            final Boolean tooSimilar = areLinesTooSimilar(tokenThis, tokenThat);
                            if (tooSimilar != null) {
                                scoreViaRemainingLines_this--;
                                scoreViaRemainingLines_that--;
                                break;
                            }

                        }
                    }

                    if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) {
                        throw new Error();
                    }

                    final double scoreActual_this = scoreViaRemainingLines_this / (double) dtlThisTokenCount;
                    final double scoreActual_that = scoreViaRemainingLines_that / (double) dtlThatTokenCount;


                    if (scoreViaRemainingLines_this < scoreViaRemainingLines_that) {
                        if (scoreActual_this < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(i);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThat);
                            break; // IMPORTANT.
                        }
                    } else {
                        if (scoreActual_that < MIN_REMAININGLINES_PERCENTAGEOF_ALLLINES) {
                            final DumbTokenList removed = ret.remove(ii);
                            //                            System.err.println("\nREMOVED:\n" + removed + "\nKEPT   :\n" + dtlThis);
                            break; // IMPORTANT.
                        }
                    }


                }

            }
        }

        return ret;
    }


}

1
为了使此命令运行,我使用了以下命令javac "C:\Users\MLM\Downloads\CrappyChromeNotificationHistoryReader.java"((编译)和 java -cp C:\Users\MLM\Downloads CrappyChromeNotificationHistoryReader(运行)):脚本失败了,if (scoreViaRemainingLines_this < 0 || scoreViaRemainingLines_that < 0) {所以我注释掉了所有解析,doTheInsaneParsingThingSystem.out.println(sb.toString());在将令牌添加到列表中时打印了所有内容。看起来“平台通知”仅处理服务器工作程序推送通知。
MLM

@MLM:感谢您提供javac信息。关于问题:如果将源粘贴到打开的Java 8 IntelliJ项目中,输入用户名(“文件”变量),然后运行代码,则对我有用。
Dreamspace总裁
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.