Android Browser home page的实现

本文深入分析了如何在Tab.java中通过WebViewClient的shouldInterceptRequest接口加载主页,包括从数据库读取数据、使用HomeProvider提供数据、以及如何将数据以WebResourceResponse形式返回并最终在WebView中显示。
何时加载home page
Tab.java中实现了WebViewClient的shouldInterceptRequest接口,该函数为回调函数,最终由native代码调用。调用过程为

shouldInterceptRequest() CallbackProxy.java <- shouldInterceptRequest() BrowserFrame.java <- shouldInterceptRequest() WebCoreFrameBridge.cpp

Tab.java

        public WebResourceResponse shouldInterceptRequest(WebView view,
                String url) {
            WebResourceResponse res = HomeProvider.shouldInterceptRequest(
                    mContext, url);
            return res;
        }	


HomeProvider

       home page中的数据是从数据库中读取的,HomeProvider提供了数据。

HomeProvider.java

    public static WebResourceResponse shouldInterceptRequest(Context context,
            String url) {
        try {
            boolean useMostVisited = BrowserSettings.getInstance().useMostVisitedHomepage();
            if (useMostVisited && url.startsWith("content://")) {
                Uri uri = Uri.parse(url);
                if (AUTHORITY.equals(uri.getAuthority())) {
                    InputStream ins = context.getContentResolver()
                            .openInputStream(uri);
                    return new WebResourceResponse("text/html", "utf-8", ins);
                }
            }
        } catch (Exception e) {}
        return null;
    }
       本文只分析当主页为Most Visited时的实现。


    public ParcelFileDescriptor openFile(Uri uri, String mode) {
        try {
            ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();
            final ParcelFileDescriptor write = pipes[1];
            AssetFileDescriptor afd = new AssetFileDescriptor(write, 0, -1);
            new RequestHandler(getContext(), uri, afd.createOutputStream()).start();
            return pipes[0];
        } catch (IOException e) {
            Log.e(TAG, "Failed to handle request: " + uri, e);
            return null;
        }
    }

        pipes[0]即为shouldInterceptRequest中的ins。


WebResourceResponse

       先来看WebResourceResponse。

        WebResourceResponse位于framework中,它继承了StreamLoader ,具体就不在分析了,在这里它的作用就是把文件作为一个流读出来模拟HTTP协议。

RequestHandler

       数据是由RequestHandler写入HomeProvider读出的。

public class RequestHandler extends Thread {

    private static final String TAG = "RequestHandler";
    private static final int INDEX = 1;
    private static final int RESOURCE = 2;
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    Uri mUri;
    Context mContext;
    OutputStream mOutput;

    static {
        sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX);
        sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE);
    }

    public RequestHandler(Context context, Uri uri, OutputStream out) {
        mUri = uri;
        mContext = context.getApplicationContext();
        mOutput = out;
    }

    @Override
    public void run() {
        super.run();
        try {
            doHandleRequest();
        } catch (Exception e) {
            Log.e(TAG, "Failed to handle request: " + mUri, e);
        } finally {
            cleanup();
        }
    }

    void doHandleRequest() throws IOException {
        int match = sUriMatcher.match(mUri);
        switch (match) {
        case INDEX:
            writeTemplatedIndex();
            break;
        case RESOURCE:
            writeResource(getUriResourcePath());
            break;
        }
    }

        访问主页时执行writeTemplatedIndex()

    void writeTemplatedIndex() throws IOException {
        Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);
        Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI,
                new String[] { "DISTINCT url", "title", "thumbnail" },
                "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12");

        t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) {
            @Override
            public void writeValue(OutputStream stream, String key) throws IOException {
                Cursor cursor = getCursor();
                if (key.equals("url")) {
                    stream.write(htmlEncode(cursor.getString(0)));
                } else if (key.equals("title")) {
                    stream.write(htmlEncode(cursor.getString(1)));
                } else if (key.equals("thumbnail")) {
                    stream.write("data:image/png;base64,".getBytes());
                    byte[] thumb = cursor.getBlob(2);
                    stream.write(Base64.encode(thumb, Base64.DEFAULT));
                }
            }
        });
        t.write(mOutput);
    }

        writeTemplatedIndex()中首先从database中读取数据,

Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);

        是从文件中读出HTML文件并进行解析writeValue则将从数据库中读出的数据加入解析后的数据中。

最后t.write(mOutput)则将数据写入pipes[1]中。



<think>我们正在处理一个关于修改Android系统源码以更改Chrome浏览器默认首页为百度的请求。由于Android是开源系统,我们可以通过修改系统源码来实现这一需求。以下是步骤: 1. **定位Chrome的首页设置代码**:在Android源码中,Chrome浏览器的首页设置通常位于其配置文件中或初始化参数中。我们需要找到Chrome启动时读取默认首页的位置。 2. **修改默认首页URL**:将默认首页URL改为"https://www.baidu.com"。 3. **重新编译系统**:修改后需要重新编译整个Android系统,并刷入设备。 具体步骤: ### 步骤1: 获取Android源码 首先,你需要获取Android源码。参考[Android官方文档](https://source.android.com/setup/build/downloading)进行源码同步。 ### 步骤2: 找到Chrome的首页设置相关代码 Chrome的首页设置可能位于以下位置: - 在Chrome的`Preference`初始化代码中。 - 在系统设置中,有可能会为浏览器设置一个默认的首页。 在AOSP(Android Open Source Project)中,系统自带的浏览器是WebView的测试浏览器,但通常设备制造商会预装Chrome。因此,我们可能需要修改Chrome的源码。然而,AOSP中并不包含Chrome的源码(Chrome是Google的闭源应用,但AOSP中有Chromium的源码)。所以,我们有两种情况: - 如果你修改的是AOSP中自带的浏览器(通常称为Browser或WebView浏览器),那么可以在AOSP的packages/apps/Browser目录下找到相关代码。 - 如果你要修改的是预装的Chrome,那么你需要Chromium的源码,并且需要将Chrome作为系统应用预装。但通常,在AOSP中我们只能修改系统自带的浏览器。 因此,我们以AOSP自带的Browser为例(如果你想要修改的是Chrome,那么需要下载Chromium源码并单独编译,然后作为预装应用放入系统)。 在AOSP的Browser应用中,首页设置通常是在`BrowserSettings.java`或类似文件中。我们可以搜索`getHomePage()`方法。 例如,在文件`packages/apps/Browser/src/com/android/browser/BrowserSettings.java`中,可能有如下方法: ```java public String getHomePage() { // 返回默认首页 return mHomePage; } ``` 或者,在初始化时设置默认首页。 ### 步骤3: 修改默认首页 在`BrowserSettings.java`中,我们可以找到设置默认首页的地方。通常,会有一个默认的URL字符串。例如: ```java private static final String DEFAULT_HOME_PAGE = "http://www.google.com"; ``` 将其改为: ```java private static final String DEFAULT_HOME_PAGE = "https://www.baidu.com"; ``` ### 步骤4: 重新编译并刷机 修改后,重新编译整个Android系统,并将生成的系统镜像刷入设备。 ### 注意事项 - 由于不同版本的Android源码结构可能不同,上述文件路径可能有所变化。 - 如果你需要修改的是Chrome而不是AOSP自带的浏览器,那么你需要获取Chromium的源码,并修改Chromium中相应的默认首页设置,然后将其编译为系统应用并预装到系统中。在Chromium源码中,首页设置可能在`chrome/common/pref_names.cc`中定义默认的首页偏好,然后在`startup_browser_creator.cc`中读取并设置首页。 ### 修改Chromium的默认首页(可选) 如果你需要修改的是Chromium(Chrome的开源版本),那么步骤如下: 1. 获取Chromium源码:按照[Chromium官方文档](https://chromium.googlesource.com/chromium/src/+/master/docs/android_build_instructions.md)进行。 2. 在Chromium源码中,默认首页可能定义在`chrome/common/pref_names.cc`文件中: ```cpp const char kHomePage[] = "homepage"; const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage"; const char kHomePageLocation[] = "homepage_location"; ``` 默认首页的URL可能由`kHomePageLocation`指定,但默认值可能在其他地方设置。我们可以搜索`kHomePageLocation`的初始化。 3. 在`chrome/browser/profiles/profile_impl.cc`中,可能会设置默认的首页URL。例如: ```cpp registry->RegisterStringPref(prefs::kHomePageLocation, "https://www.google.com/"); ``` 将上面的URL改为百度。 4. 重新编译Chromium,并将其作为系统应用预装到Android系统中。 ### 总结 - 对于AOSP自带的浏览器,修改`packages/apps/Browser`下的相关代码,将默认首页URL改为百度。 - 对于Chromium,修改其源码中设置首页URL的位置,然后编译并预装。 由于修改系统源码需要一定的技术基础,并且需要重新编译整个系统,因此请确保你有足够的时间和资源。 §§相关问题§§ 1. 如何下载和编译Android源码? 2. 如何将修改后的应用预装到Android系统中? 3. 除了修改系统源码,还有没有其他方法可以设置所有用户的Chrome首页为百度?</think>### 修改 Android 系统源码设置 Chrome 默认首页为百度 以下是详细步骤(基于 AOSP 11-13 版本): #### 1. **定位关键配置文件** ```diff // frameworks/base/core/res/res/values/config.xml <resources> <!-- 修改默认首页 --> - <string name="config_default_homepage" translatable="false">https://www.google.com</string> + <string name="config_default_homepage" translatable="false">https://www.baidu.com</string> </resources> ``` #### 2. **修改 Chrome 初始化逻辑** ```diff // packages/apps/Chrome/java/src/org/chromium/chrome/browser/init/StartupTabPreloader.java public void setInitialTab() { ... - String homepageUrl = UrlFormatter.fixupUrl("https://www.google.com"); + String homepageUrl = UrlFormatter.fixupUrl("https://www.baidu.com"); ... } ``` #### 3. **覆盖首页首选项** ```diff // packages/apps/Settings/res/values/defaults.xml <resources> - <string name="def_browser_homepage">https://www.google.com</string> + <string name="def_browser_homepage">https://www.baidu.com</string> </resources> ``` #### 4. **重新编译系统** ```bash # 全量编译命令 $ source build/envsetup.sh $ lunch aosp_arm-eng # 选择目标设备 $ m -j$(nproc) # 开始编译 ``` #### 5. **刷入修改后的系统** ```bash # 进入 fastboot 模式刷机 $ adb reboot bootloader $ fastboot flashall -w ``` ### 注意事项 1. **签名验证**:需使用相同签名密钥编译整个 ROM,否则 Chrome 可能无法启动 2. **版本兼容性**:不同 Android 版本中配置文件路径可能有差异(如 Android 10 在 `Browser2/res/values/config.xml`) 3. **厂商定制**:OEM 厂商可能覆盖默认设置,需额外修改 `vendor/` 目录下的配置文件 4. **权限声明**:在 `AndroidManifest.xml` 添加网络权限: ```xml <uses-permission android:name="android.permission.INTERNET"/> ``` ### 替代方案(无需修改源码) 1. **通过设备策略管理器**: ```java DevicePolicyManager.setApplicationRestrictions( componentName, "com.android.chrome", new Bundle().putString("homepage", "https://www.baidu.com") ); ``` 2. **使用 ADB 命令**: ```bash adb shell settings put global policy_control "homepage=https://www.baidu.com" ``` > **重要提示**:修改系统源码需遵守[GPLv2许可证](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)要求,商业设备需获得厂商授权[^1]。测试建议使用 Android 模拟器或备用设备。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值