WordPress中判断用户是不是管理员

自定义`WordPress`插件的时候,需要判断当前用户的角色是不是网站管理员,如果是管理员的情况下才允许使用插件功能,否则禁止使用。

对于自定义主题的情况,可以使用如下代码:

function is_administrator() {
  // wp_get_current_user函数仅限在主题的functions.php中使用
  $currentUser = wp_get_current_user();

  if(!empty($currentUser->roles) && in_array('administrator', $currentUser->roles)) 
    return True;  // 是管理员
  else
    return False;  // 非管理员
}

对于自定义插件的情况,可以使用如下代码:

function is_administrator() {
  if( is_user_logged_in() ) {
    //用户已登录,检查用户角色
    global $current_user;
    if((!empty($current_user)) && (!empty($current_user->roles)) && in_array('administrator', $current_user->roles)) 
      return True;  // 是管理员
  }
  return False;  // 非管理员
}

更简单的代码如下:

function is_administrator() {
  if( current_user_can( 'manage_options' ) ) { return True; }
  return False;  // 非管理员
}

参考连接


ubuntu 18.04系统报错ModuleNotFoundError: No module named 'pip._internal'

重新安装的ubuntu 18.04系统上初次安装`python3-pip`之后,执行升级命令,出现如下错误信息:

$ sudo apt-get install python3-pip

$ sudo pip3 install --upgrade pip
Traceback (most recent call last):
  File "/usr/local/bin/pip3", line 7, in <module>
    from pip._internal import main
ModuleNotFoundError: No module named 'pip._internal'

解决方法为重新升级安装一次 pip,如下:

$ python3 -m pip install --upgrade pip

参考链接


No module named 'pip._internal.cli.main'

Error: Cask 'java7' is unreadable: undefined method `undent' for #

今天在执行`brew upgrade`的时候出现如下错误:

$ brew upgrade    
Updating Homebrew...
Error: Cask 'java7' is unreadable: undefined method `undent' for #<String:0x00007fcff5421ec8>

原因为某次更新之后,配置文件增加了某些不必要的字段。更要命的是,不能执行卸载命令来删除出问题的安装包。解决方法为删除这个字段。

方案如下:

$ find "$(brew --prefix)/Caskroom/"java7'/.metadata' -type f -name '*.rb' | xargs grep 'EOS.undent' --files-with-matches | xargs sed -i '' 's/EOS.undent/EOS/'

$ find "$(brew --prefix)/Caskroom/"java'/.metadata' -type f -name '*.rb' | xargs grep 'EOS.undent' --files-with-matches | xargs sed -i '' 's/EOS.undent/EOS/'

$ brew uninstall java7

$ brew cleanup

$ brew update

$ brew upgrade

参考链接


undefined method `undent' #49716

Android WebView/X5截长图解决方案

  1. 普通`WebView`如何截取长图
  2. 针对`X5内核中WebView`如何截取长图

日常开发中,遇到为`WebView`截取长图算是一种常见的需求。网上聪明的程序员们提供了多种截取`WebView`长图的方法,这为我们的开发提供了很多便利。现在,也有很多APP是集成了X5内核的,网上对于X5内核的截长图方案介绍比较少,所以这里我整理了对`WebView`截取长图的比较通用可行的方法,并且对使用了x5内核的`WebView`的截图方法进行分享。

普通`WebView`截长图方案

普通`WebView`截取长图,这里是指项目中没有集成X5内核的情况。利用`Google`文档上的api可以顺利截图。以`Android5.0`为版本分界线,截图采用不同的处理方式。

1. Android5.0以下版本

    /**
     * 对WebView进行截屏,虽然使用过期方法,但在当前Android版本中测试可行
     *
     * @param webView
     * @return
     */
    private static Bitmap captureWebViewKitKat(WebView webView) {
            Picture picture = webView.capturePicture();
            int width = picture.getWidth();
            int height = picture.getHeight();
            if (width > 0 && height > 0) {
                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
                Canvas canvas = new Canvas(bitmap);
                picture.draw(canvas);
                return bitmap;
            }
            return null;
        }
    }

2. Android5.0及以上版本

在Android5.0及以上版本,Android对`WebView`进行了优化,为了减少内存使用和提高性能,使用`WebView`加载网页时只绘制显示部分。如果我们不做处理,仍然使用上述代码截图的话,就会出现只截到屏幕内显示的`WebView`内容,其它部分是空白的情况。
这时候,我们通过调用`WebView.enableSlowWholeDocumentDraw()`方法可以关闭这种优化,但要注意的是,该方法需要在`WebView`实例被创建前就要调用,否则没有效果。

另外这个方法一旦开启,会影响到整个进程中的`WebView`实例,并且没有办法关闭。

这个代码的本质是设置了一个全局变量,并且没有提供关闭接口。其真实调用的代码如下:

     private static boolean sRecordWholeDocumentEnabledByApi = false;
     static void enableSlowWholeDocumentDraw() {
          sRecordWholeDocumentEnabledByApi = true;
     }

我们在`WebView`实例被创建前加入代码:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        android.webkit.WebView.enableSlowWholeDocumentDraw();
    }

另外,当应用存在多个进程的时候,比如消息推送进程,LBS定位进程存在的情况下,务必确保只在主进程中初始化这个设置,否则运行时可能报错。

根据`Google`文档中描述,`capturePicture()`方法已不鼓励使用,推荐我们通过`webView`的`onDraw(Canvas)`去获取图像,所以这里我们去拿到网页的宽高后,就调用`webView.draw(Canvas)`方法生成`webView`截图。

    private void captureWebViewLollipop(WebView webView) {
        float scale = webView.getScale();
        int width = webView.getWidth();
        int height = (int) (webView.getContentHeight() * scale + 0.5);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        webView.draw(canvas);
        return bitmap;
    }

X5内核截取长图

使用X5内核截取长图有两种方法,并且都可以不用考虑版本问题,这为我们提供了方便。在X5内核下,如果使用`WebView`的`onDraw(Canvas)`方法,会出现或多或少的问题,所以对这个方法弃坑了。以下是两个截图方法:

1. 使用X5内核方法`snapshotWholePage(Canvas, boolean, boolean)`

在`X5`内核中提供了一个截取整个`WebView`界面的方法`snapshotWholePage(Canvas, boolean, boolean)`,但是这个方法有个缺点,就是不以屏幕上`WebView`的宽高截图,只是以`WebView`的`contentWidth`和`contentHeight`为宽高截图,所以截出来的图片会不怎么清晰,但作为缩略图效果还是不错了。

    private static Bitmap captureX5WebViewUnsharp(Context context, WebView webView) {
        if (webView == null) {
            return null;
        }
        if (context == null) {
            context = webView.getContext();
        }
        int width = webView.getContentWidth();
        int height = webView.getContentHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Canvas canvas = new Canvas(bitmap);
        webView.getX5WebViewExtension().snapshotWholePage(canvas, false, false);
        return bitmap;
    }

2. 使用`capturePicture()`截取清晰长图

如果想要在`X5`内核下截到清晰的长图,不能使用`snapshotWholePage()`,依然可以采用`capturePicture()`。X5内核下使用`capturePicture()`进行截图,可以直接拿到`WebView`的清晰长图,但这是个`Deprecated`的方法,使用的时候要做好异常处理。

总结

以上是`WebView`截长图方法的总结和分享,对X5内核的截图也是尝试了多种途径最后找到满意的解决方案。另外,截长图会占用大量内存,容易触发OOM,所以代码中也要注意对OOM的处理。

在使用了`X5`内核的项目中,使用`WebView`截取长图的判断逻辑可以是:

// 有x5内核没有生效,并且Android版本是5.0及以上时,调用enableSlowWholeDocumentDraw()方便截取长图
    if (!isX5Enabled() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        android.webkit.WebView.enableSlowWholeDocumentDraw();
    }
/* 创建WebView ×/

...

// 网页截图
    public void captureWholePage() {
        try {
            Bitmap bitmap = captureWebView();
            /* 对拿到的bitmap根据需要进行处理 */
        } catch (OutOfMemoryError oom) {
            /* 对OOM做处理
        }
    }

目前(`2020/08/01`)之前版本的`X5 SDK`,如果编译`APK`的时候指定`targetSdkVersion`版本高于 `28`(`Android O`)的情况下,调用`snapshotWholePage(Canvas, boolean, boolean)`可能会无法获取到截图,图片内容全黑。

观察日志发生如下报错:

2020-07-31 17:14:18.538 16536-16536/com.xxxx.xxx W/com.xxxx.xxx: Accessing hidden field Landroid/graphics/Canvas;->mBitmap:Landroid/graphics/Bitmap; (greylist-max-p, reflection, denied)
2020-07-31 17:14:18.539 16536-16536/com.xxxx.xxx W/System.err: java.lang.NoSuchFieldException: No field mBitmap in class Landroid/graphics/Canvas; (declaration of 'android.graphics.Canvas' appears in /system/framework/framework.jar)
2020-07-31 17:14:18.540 16536-16536/com.xxxx.xxx W/System.err:     at java.lang.Class.getDeclaredField(Native Method)
2020-07-31 17:14:18.540 16536-16536/com.xxxx.xxx W/System.err:     at com.tencent.smtt.os.SMTTAdaptation.a(TbsJavaCore:115)
2020-07-31 17:14:18.540 16536-16536/com.xxxx.xxx W/System.err:     at com.tencent.smtt.webkit.WebViewChromiumExtension.a(TbsJavaCore:2519)
2020-07-31 17:14:18.540 16536-16536/com.xxxx.xxx W/System.err:     at com.tencent.tbs.core.webkit.tencent.TencentWebViewProxy.snapshotWholePage(TbsJavaCore:2366)
2020-07-31 17:14:18.540 16536-16536/com.xxxx.xxx W/System.err:     at com.tencent.tbs.core.webkit.adapter.X5WebViewAdapter.snapshotWholePage(TbsJavaCore:851)

原因为从`API 29`(`Android P`)开始,`Google`对于某些反射调用私有方法的行为进行了限制,比如动态反射赋值`android.graphics.Canvas.java`的私有变量`mBitmap`。这些调用会被抛出异常阻止。

参考链接